View Source Reactor (reactor v0.2.4)

Reactor is a dynamic, concurrent, dependency resolving saga orchestrator.

usage

Usage

You can construct a reactor using the Reactor Spark DSL:

defmodule HelloWorldReactor do
  @moduledoc false
  use Reactor

  input :whom

  step :greet, Greeter do
    argument :whom, input(:whom)
  end

  return :greet
end
iex> Reactor.run(HelloWorldReactor, %{whom: "Dear Reader"})
{:ok, "Hello, Dear Reader!"}

or you can build it programmatically:

iex> reactor = Builder.new()
...> {:ok, reactor} = Builder.add_input(reactor, :whom)
...> {:ok, reactor} = Builder.add_step(reactor, :greet, Greeter, whom: {:input, :whom})
...> {:ok, reactor} = Builder.return(reactor, :greet)
...> Reactor.run(reactor, %{whom: nil})
{:ok, "Hello, World!"}

dsl-documentation

DSL Documentation

index

Index

  • reactor
    • input
    • step
      • argument
    • compose
      • argument

docs

Docs

reactor

reactor

The top-level reactor DSL


  • :return (atom/0) - Specify which step result to return upon completion.

input

input

Specifies an input to the Reactor.

An input is a value passed in to the Reactor when executing. If a Reactor were a function, these would be it's arguments.

Inputs can be transformed with an arbitrary function before being passed to any steps.

Examples:

input :name
input :age do
  transform &String.to_integer/1
end
  • :name (atom/0) - Required. A unique name for this input.
    The name is used to allow steps to depend on it.

  • :transform - An optional transformation function which can be used to modify the input before it is passed to any steps. The default value is nil.

step

step

Specifies a Reactor step.

Steps are the unit of work in a Reactor. Reactor will calculate the dependencies graph between the steps and execute as many as it can in each iteration.

See the Reactor.Step behaviour for more information.

Examples:

step :create_user, MyApp.Steps.CreateUser do
  argument :username, input(:username)
  argument :password_hash, result(:hash_password)
end
step :hash_password do
  argument :password, input(:password)

  impl fn %{password: password}, _ ->
    {:ok, Bcrypt.hash_pwd_salt(password)}
  end
end
  • :name (atom/0) - Required. A unique name for the step.
    This is used when choosing the return value of the Reactor and for arguments into another step.

  • :impl - Required. The step implementation.
    The implementation can be either a module which implements the Reactor.Step behaviour or an anonymous function or function capture with an arity of 2.
    Note that steps which are implemented as functions cannot be compensated or undone.

  • :max_retries - The maximum number of times that the step can be retried before failing.
    This is only used when the result of the compensate/4 callback is :retry. The default value is :infinity.

  • :async? (boolean/0) - When set to true the step will be executed asynchronously via Reactor's TaskSupervisor. The default value is true.

  • :transform - An optional transformation function which can be used to modify the entire argument map before it is passed to the step. The default value is nil.

argument

Specifies an argument to a Reactor step.

Each argument is a value which is either the result of another step, or an input value.

Individual arguments can be transformed with an arbitrary function before being passed to any steps.

Examples:

argument :name, input(:name)
argument :user, result(:create_user)
argument :user_id, result(:create_user) do
  transform & &1.id
end
argument :three, value(3)
  • :name (atom/0) - Required. The name of the argument which will be used as the key in the arguments map passed to the implementation.

  • :source - Required. What to use as the source of the argument.
    See Reactor.Argument.Templates for more information.

  • :transform - An optional transformation function which can be used to modify the argument before it is passed to the step. The default value is nil.

compose

compose

Compose another Reactor into this one.

Allows place another Reactor into this one as if it were a single step.

  • argument

  • :name (atom/0) - Required. A unique name for the step.
    Allows the result of the composed reactor to be depended upon by steps in this reactor.

  • :reactor - Required. The reactor module or struct to compose upon.

argument

Specifies an argument to a Reactor step.

Each argument is a value which is either the result of another step, or an input value.

Individual arguments can be transformed with an arbitrary function before being passed to any steps.

Examples:

argument :name, input(:name)
argument :user, result(:create_user)
argument :user_id, result(:create_user) do
  transform & &1.id
end
argument :three, value(3)
  • :name (atom/0) - Required. The name of the argument which will be used as the key in the arguments map passed to the implementation.

  • :source - Required. What to use as the source of the argument.
    See Reactor.Argument.Templates for more information.

  • :transform - An optional transformation function which can be used to modify the argument before it is passed to the step. The default value is nil.

Link to this section Summary

Link to this section Types

@type context() :: Enumerable.t({any(), any()})
@type inputs() :: %{optional(atom()) => any()}
@type options() ::
  Enumerable.t(
    {:max_concurrency, pos_integer()}
    | {:timeout, pos_integer() | :infinity}
    | {:max_iterations, pos_integer() | :infinity}
    | {:halt_timeout, pos_integer() | :infinity}
  )
@type state() :: :pending | :executing | :halted | :failed | :successful
@type t() :: %Reactor{
  context: context(),
  id: any(),
  inputs: [atom()],
  intermediate_results: %{required(any()) => any()},
  plan: nil | Graph.t(),
  return: any(),
  state: state(),
  steps: [Reactor.Step.t()],
  undo: [{Reactor.Step.t(), any()}]
}

Link to this section Functions

Link to this function

run(reactor, inputs \\ %{}, context \\ %{}, options \\ [])

View Source
@spec run(t() | module(), inputs(), context(), options()) ::
  {:ok, any()} | {:error, any()} | {:halted, t()}

Run a reactor.