View Source Reactor (reactor v0.5.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!"}
Hooks
Reactor allows you to add lifecycle hooks using functions in
Reactor.Builder
. Lifecycle hooks will be called in the order that they are
added to the reactor.
Four kinds of lifecycle hooks are provided:
complete
- These hooks will be called with the result of the reactor run when the run is successful. If you return{:ok, new_result}
then the result is replaced with the new value.error
- These hooks will be called with an error (or list of errors) which were raised or returned during the reactor run. You can either return:ok
or a new error tuple to replace the error result.halt
- These hooks are called when the reactor is being halted and allows you to mutate the context before the halted reactor is returned.init
- These hooks are called when the reactor is first run or is resumed from a previous halted state and allow you to mutate the context before the reactor run is started.
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 t() :: %Reactor{ context: context(), hooks: %{ optional(:complete) => [complete_hook()], optional(:error) => [error_hook()], optional(:halt) => [halt_hook()], optional(:init) => [init_hook()] }, 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()}] }
@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
.