View Source Getting Started with Handoff

This guide will help you get started with Handoff, a library for building and executing Directed Acyclic Graphs (DAGs) of functions in Elixir.

installation

Installation

Add handoff to your list of dependencies in mix.exs:

def deps do
  [
    {:handoff, "~> 0.1.0"}
  ]
end

Then run:

mix deps.get

basic-usage

Basic Usage

starting-handoff

Starting Handoff

Handoff is started by default when included as a dependency. Handoff.start is available for more granular control.

creating-a-simple-dag

Creating a Simple DAG

Let's create a simple computation graph:

alias Handoff.Function

# Create a new DAG
dag = Handoff.new()

# Define a source function with no dependencies
source_fn = %Function{
  id: :data_source,
  args: [],
  code: &Elixir.Function.identity/1
  extra_args: [[1, 2, 3, 4, 5]]
}

defmodule MyModule do
  def double(x) do
    x * 2
  end
end

# Define a transformation function
transform_fn = %Function{
  id: :double,
  args: [:data_source],
  code: &Enum.map/2,
  extra_args: [&MyModule.double/1]
}

# Define a final aggregation function
aggregate_fn = %Function{
  id: :sum,
  args: [:double],
  code: &Enum.sum/1,
  argument_inclusion: :as_list # this will pass the list of arguments as a single list argument
}

# Add functions to the DAG
dag =
  dag
  |> Handoff.DAG.add_function(source_fn)
  |> Handoff.DAG.add_function(transform_fn)
  |> Handoff.DAG.add_function(aggregate_fn)

# Validate the DAG
:ok = Handoff.DAG.validate(dag)

executing-the-dag

Executing the DAG

# Execute the DAG
{:ok, results} = Handoff.execute(valid_dag)

# Access the final result
sum_result = results[:sum]
IO.puts("The sum is: #{sum_result}")  # Output: The sum is: 30

using-extra-arguments

Using Extra Arguments

You can provide additional arguments to functions at execution time:

# Define a function that uses extra arguments
parametrized_fn = %Function{
  id: :parametrized,
  args: [:data_source],
  code: &IO.inspect/2,
  extra_args: [[label: "inspected with options"]]
}

error-handling

Error Handling

Handoff provides proper error handling during validation and execution:

# DAG with missing dependencies
invalid_dag =
  Handoff.new()
  |> Handoff.DAG.add_function(%Function{
    id: :invalid,
    args: [:non_existent],  # This dependency doesn't exist
    code: &SomeModule.some_function/1
  })

case Handoff.DAG.validate(invalid_dag) do
  :ok ->
    IO.puts("DAG is valid")

  {:error, {:missing_function, missing}} ->
    IO.puts("DAG has missing function: #{inspect(missing)}")
end

next-steps

Next Steps

Now that you understand the basics of Handoff, you might want to explore: