View Source Reactor (reactor v0.3.2)
Reactor is a dynamic, concurrent, dependency resolving saga orchestrator.
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
Index
- reactor
around
- argument
- wait_for
debug
- argument
- wait_for
group
- argument
- wait_for
input
step
- argument
- wait_for
switch
matches?
default
compose
- argument
- wait_for
Docs
reactor
The top-level reactor DSL
- argument
- wait_for
- argument
- wait_for
- argument
- wait_for
- argument
- wait_for
matches?
default
- argument
- wait_for
:return
(atom/0
) - Specify which step result to return upon completion.
around
Wrap a function around a group of steps.
:name
(atom/0
) - Required. A unique name of the group of steps.:fun
- Required. The around function.
SeeReactor.Step.Around
for more information.:allow_async?
(boolean/0
) - Whether the emitted steps should be allowed to run asynchronously.
Passed to the child Reactor as it'sasync?
option. The default value isfalse
.
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 :year, input(:date, [:year])
argument :user, result(:create_user)
argument :user_id, result(:create_user) do
transform & &1.id
end
argument :user_id, result(:create_user, [:id])
argument :three, value(3)
:name
(atom/0
) - Required. The name of the argument which will be used as the key in thearguments
map passed to the implementation.:source
- Required. What to use as the source of the argument.
SeeReactor.Dsl.Argument
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 isnil
.
wait_for
Wait for the named step to complete before allowing this one to start.
Desugars to argument :_, result(step_to_wait_for)
Examples:
wait_for :create_user
:names
- Required. The name of the step to wait for.
debug
Inserts a step which will send debug information to the Logger
.
Examples:
debug :debug do
argument :suss, result(:suss_step)
end
:name
(atom/0
) - Required. A unique identifier for the step.:level
- The log level to send the debug information to. Valid values are :emergency, :alert, :critical, :error, :warning, :notice, :info, :debug The default value is:debug
.
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 :year, input(:date, [:year])
argument :user, result(:create_user)
argument :user_id, result(:create_user) do
transform & &1.id
end
argument :user_id, result(:create_user, [:id])
argument :three, value(3)
:name
(atom/0
) - Required. The name of the argument which will be used as the key in thearguments
map passed to the implementation.:source
- Required. What to use as the source of the argument.
SeeReactor.Dsl.Argument
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 isnil
.
wait_for
Wait for the named step to complete before allowing this one to start.
Desugars to argument :_, result(step_to_wait_for)
Examples:
wait_for :create_user
:names
- Required. The name of the step to wait for.
group
Call functions before and after a group of steps.
:name
(atom/0
) - Required. A unique name for the group of steps.:before_all
- Required. The before function.
SeeReactor.Step.Group
for more information.:after_all
- Required. The after function.
SeeReactor.Step.Group
for more information.:allow_async?
(boolean/0
) - Whether the emitted steps should be allowed to run asynchronously.
Passed to the child Reactor as it'sasync?
option. The default value istrue
.
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 :year, input(:date, [:year])
argument :user, result(:create_user)
argument :user_id, result(:create_user) do
transform & &1.id
end
argument :user_id, result(:create_user, [:id])
argument :three, value(3)
:name
(atom/0
) - Required. The name of the argument which will be used as the key in thearguments
map passed to the implementation.:source
- Required. What to use as the source of the argument.
SeeReactor.Dsl.Argument
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 isnil
.
wait_for
Wait for the named step to complete before allowing this one to start.
Desugars to argument :_, result(step_to_wait_for)
Examples:
wait_for :create_user
:names
- Required. The name of the step to wait for.
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 isnil
.
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)
run 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
- The step implementation.
Provides an implementation for the step with the named module. The module must implement theReactor.Step
behaviour.:run
- Provide an anonymous function which implements therun/3
callback.
You cannot provide this option at the same time as theimpl
argument.:undo
- Provide an anonymous function which implements theundo/4
callback.
You cannot provide this option at the same time as theimpl
argument.:compensate
- Provide an anonymous function which implements theundo/4
callback.
You cannot provide this option at the same time as theimpl
argument.:max_retries
- The maximum number of times that the step can be retried before failing.
This is only used when the result of thecompensate/4
callback is:retry
. The default value is:infinity
.:async?
(boolean/0
) - When set to true the step will be executed asynchronously via Reactor'sTaskSupervisor
. The default value istrue
.: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 isnil
.
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 :year, input(:date, [:year])
argument :user, result(:create_user)
argument :user_id, result(:create_user) do
transform & &1.id
end
argument :user_id, result(:create_user, [:id])
argument :three, value(3)
:name
(atom/0
) - Required. The name of the argument which will be used as the key in thearguments
map passed to the implementation.:source
- Required. What to use as the source of the argument.
SeeReactor.Dsl.Argument
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 isnil
.
wait_for
Wait for the named step to complete before allowing this one to start.
Desugars to argument :_, result(step_to_wait_for)
Examples:
wait_for :create_user
:names
- Required. The name of the step to wait for.
switch
Use a predicate to determine which steps should be executed.
:name
(atom/0
) - Required. A unique name for the switch.:allow_async?
(boolean/0
) - Whether the emitted steps should be allowed to run asynchronously. The default value istrue
.:on
- Required. The value to match against.
matches?
A group of steps to run when the predicate matches.
:predicate
- Required. A one-arity function which is used to match the switch input.
If the switch returns a truthy value, then the nested steps will be run.:allow_async?
(boolean/0
) - Whether the emitted steps should be allowed to run asynchronously. The default value istrue
.:return
(atom/0
) - Specify which step result to return upon completion.
default
If none of the matches?
branches match the input, then the default
steps will be run if provided.
:return
(atom/0
) - Specify which step result to return upon completion.
compose
Compose another Reactor into this one.
Allows place another Reactor into this one as if it were a single step.
: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 :year, input(:date, [:year])
argument :user, result(:create_user)
argument :user_id, result(:create_user) do
transform & &1.id
end
argument :user_id, result(:create_user, [:id])
argument :three, value(3)
:name
(atom/0
) - Required. The name of the argument which will be used as the key in thearguments
map passed to the implementation.:source
- Required. What to use as the source of the argument.
SeeReactor.Dsl.Argument
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 isnil
.
wait_for
Wait for the named step to complete before allowing this one to start.
Desugars to argument :_, result(step_to_wait_for)
Examples:
wait_for :create_user
:names
- Required. The name of the step to wait for.
Summary
Types
When set to false
forces the Reactor to run every step synchronously,
regardless of the step configuration.
Use a Reactor.Executor.ConcurrencyTracker.pool_key
to allow this Reactor to
share it's concurrency pool with other Reactor instances.
How long to wait for asynchronous steps to complete when halting.
Specify the maximum number of asynchronous steps which can be run in parallel.
The maximum number of iterations which after which the Reactor will halt.
Specify the amount of execution time after which to halt processing.
Types
@type async_option() :: {:async?, boolean()}
When set to false
forces the Reactor to run every step synchronously,
regardless of the step configuration.
Defaults to true
.
@type concurrency_key_option() :: {:concurrency_key, reference()}
Use a Reactor.Executor.ConcurrencyTracker.pool_key
to allow this Reactor to
share it's concurrency pool with other Reactor instances.
If you do not specify one then the Reactor will initialise a new pool and place it in it's context for any child Reactors to re-use.
Only used if async?
is set to true
.
@type context_arg() :: Enumerable.t({atom(), any()})
@type halt_timeout_option() :: {:halt_timeout, pos_integer() | :infinity}
How long to wait for asynchronous steps to complete when halting.
Defaults to 5000ms.
@type max_concurrency_option() :: {:max_concurrency, pos_integer()}
Specify the maximum number of asynchronous steps which can be run in parallel.
Defaults to the result of System.schedulers_online/0
. Only used if
async?
is set to true
.
@type max_iterations_option() :: {:max_iterations, pos_integer() | :infinity}
The maximum number of iterations which after which the Reactor will halt.
Defaults to :infinity
.
@type options() :: Enumerable.t( max_concurrency_option() | timeout_option() | max_iterations_option() | halt_timeout_option() | async_option() | concurrency_key_option() )
@type state() :: :pending | :executing | :halted | :failed | :successful
@type timeout_option() :: {:timeout, pos_integer() | :infinity}
Specify the amount of execution time after which to halt processing.
Note that this is not a hard limit. The Reactor will stop when the first step completes after the timeout has expired.
Defaults to :infinity
.