View Source Reactor.Step behaviour (reactor v0.10.0)
The Step behaviour and struct.
Implement this behaviour to make steps for your Reactor.
Summary
Types
Optional capabilities which may be implemented by the step module.
Possible valid return values for the compensate/4
callback.
Possible valid return values for the run/3
callback.
Possible valid return values for the undo/4
callback.
Callbacks
Detect if the step can be run asynchronously at runtime.
Detect the capabilities of the step at runtime.
Compensate for the failure of the step.
Execute the step.
Undo a previously successful execution of the step.
Functions
Is the step able to be run asynchronously?
Find out of a step has a capability.
Compensate a step
Execute a step.
Undo a step
Types
@type capability() :: :compensate | :undo
Optional capabilities which may be implemented by the step module.
This allows us to optimise out calls steps which cannot be undone, etc.
@type compensate_result() :: {:continue, value :: any()} | :ok | :retry | {:error | :retry, reason :: any()}
Possible valid return values for the compensate/4
callback.
@type run_result() :: {:ok, value :: any()} | {:ok, value :: any(), [t()]} | :retry | {:halt | :error | :retry, reason :: any()}
Possible valid return values for the run/3
callback.
@type step() :: module()
@type t() :: %Reactor.Step{ arguments: [Reactor.Argument.t()], async?: boolean() | (keyword() -> boolean()), context: %{optional(atom()) => any()}, impl: module() | {module(), keyword()}, max_retries: non_neg_integer() | :infinity, name: any(), ref: nil | reference(), transform: nil | (any() -> any()) | {module(), keyword()} | mfa() }
@type undo_result() :: :ok | :retry | {:retry | :error, reason :: any()}
Possible valid return values for the undo/4
callback.
Callbacks
Detect if the step can be run asynchronously at runtime.
This callback is automatically defined by
use Reactor.Step
however you're free to override it if you need a specific behaviour.
This callback is called when Reactor is deciding whether to run a step asynchronously.
The default implementation of this callback checks returns the the value of
the steps's async?
key if it is boolean, or calls it with the steps's
options if it is a function.
@callback can?(step :: t(), capability()) :: boolean()
Detect the capabilities of the step at runtime.
This callback is automatically defined by
use Reactor.Step
however you're free to override it if you need specific behaviour.
Whenever Reactor would like to either undo a change made by the step, or compensate a step failure this callback is called to detect whether the step module is capable of the desired action.
The default implementation of this callback checks to see if the optional callback is defined on the current module.
@callback compensate( reason :: any(), arguments :: Reactor.inputs(), context :: Reactor.context(), options :: keyword() ) :: compensate_result()
Compensate for the failure of the step.
Do not implement this callback if your step doesn't support compensation.
If run/3
returned an error then this callback will be called the error
reason and the original arguments.
This provides you the opportunity to handle the error in a number of ways and direct the reactor as to what to do next.
Arguments
reason
- the error reason returned fromrun/3
.arguments
- the arguments passed to the step.context
- the reactor context.options
- a keyword list of options provided to the step (if any).
Return values
{:continue, value}
if you're able to provide a valid result for the step (perhaps by re-running the original computation) then return that within a:continue
tuple and execution will continue as planned.:ok
the step was successfully compensated and the reactor should continue undoing upstream changes.:retry
or{:retry, reason}
if you would like the reactor to attempt to re-run the step. You can optionally supply an error reason which will be used in the event that the step runs out of retries, otherwise aReactor.Error.Invalid.RetriesExceededError
will be used.{:error, reason}
if compensation was unsuccessful.
@callback run( arguments :: Reactor.inputs(), context :: Reactor.context(), options :: keyword() ) :: run_result()
Execute the step.
This is the function that implements the behaviour you wish to execute. You
will receive arguments as per the t:Step.t
definition along with their
corresponding values as a map and a copy of the current reactor context.
Arguments
arguments
- A map of arguments as per thet:Step.t
definition we're called from.context
- The reactor context.options
- A keyword list of options provided to the step (if any).
Return values
{:ok, value}
the step completed successfully it returns the value in an ok tuple.{:ok, value, [step]}
the step completed successfully and wants to add new steps to the reactor.{:error, reason}
the if step failed, return an error tuple.:retry
or{:retry, reason}
the step failed, but is retryable. You can optionally supply an error reason which will be used in the event that the step runs out of retries, otherwise aReactor.Error.RetriesExceededError
will be used.{:halt, reason}
terminate (or pause) reactor execution. If there are actively running steps the reactor will wait for them to finish and then return the incomplete state for later resumption.
@callback undo( value :: any(), arguments :: Reactor.inputs(), Reactor.context(), options :: keyword() ) :: undo_result()
Undo a previously successful execution of the step.
Do not implement this callback if your step doesn't support undoing.
This callback is called when the reactor encounters an unhandled error later in it's execution run and must undo the work previously done.
Arguments
value
- the return value of the previously successful call torun/3
.arguments
- the arguments passed to the step.context
- the reactor context.options
- a keyword list of options provided to the step (if any).
Return values
:ok
the step was successfully undo and the reactor should continue rolling back.{:error, reason}
there was an error while attempting to compensate. The reactor will collect the error and continue rolling back.:retry
if you would like the reactor to attempt to undo the again later- possibly in the case of a network failure for example.
Functions
Is the step able to be run asynchronously?
@spec can?(t(), capability()) :: boolean()
Find out of a step has a capability.
@spec compensate( t(), reason :: any(), arguments :: Reactor.inputs(), context :: Reactor.context() ) :: compensate_result()
Compensate a step
@spec run(t(), arguments :: Reactor.inputs(), context :: Reactor.context()) :: run_result()
Execute a step.
@spec undo( t(), value :: any(), arguments :: Reactor.inputs(), context :: Reactor.context() ) :: undo_result()
Undo a step