mirror of
https://github.com/ash-project/reactor.git
synced 2024-09-19 12:53:19 +12:00
docs: Add option schemas to public API functions and improve docs. (#99)
This commit is contained in:
parent
27a01e7862
commit
7032155f97
8 changed files with 168 additions and 12 deletions
|
@ -1,5 +1,5 @@
|
|||
defmodule Reactor do
|
||||
alias Reactor.{Dsl, Executor, Step}
|
||||
alias Reactor.{Dsl, Error.Validation.StateError, Executor, Step}
|
||||
|
||||
@moduledoc """
|
||||
Reactor is a dynamic, concurrent, dependency resolving saga orchestrator.
|
||||
|
@ -129,13 +129,58 @@ defmodule Reactor do
|
|||
steps: [Step.t()]
|
||||
}
|
||||
|
||||
@doc false
|
||||
@doc "A guard which returns true if the value is a Reactor struct"
|
||||
@spec is_reactor(any) :: Macro.t()
|
||||
defguard is_reactor(reactor) when is_struct(reactor, __MODULE__)
|
||||
|
||||
@option_schema [
|
||||
max_concurrency: [
|
||||
type: :pos_integer,
|
||||
required: false,
|
||||
doc: "The maximum number of processes to use to run the Reactor"
|
||||
],
|
||||
timeout: [
|
||||
type: {:or, [:pos_integer, {:literal, :infinity}]},
|
||||
required: false,
|
||||
default: :infinity,
|
||||
doc: "How long to allow the Reactor to run for"
|
||||
],
|
||||
max_iterations: [
|
||||
type: {:or, [:pos_integer, {:literal, :infinity}]},
|
||||
required: false,
|
||||
default: :infinity,
|
||||
doc: "The maximum number of times to allow the Reactor to loop"
|
||||
],
|
||||
async_option: [
|
||||
type: :boolean,
|
||||
required: false,
|
||||
default: true,
|
||||
doc: "Whether to allow the Reactor to start processes"
|
||||
],
|
||||
concurrency_key_option: [
|
||||
type: :reference,
|
||||
required: false,
|
||||
hide: true
|
||||
]
|
||||
]
|
||||
|
||||
@doc """
|
||||
Run a reactor.
|
||||
Attempt to run a Reactor.
|
||||
|
||||
## Arguments
|
||||
|
||||
* `reactor` - The Reactor to run, either a Reactor DSL module, or a Reactor
|
||||
struct.
|
||||
* `inputs` - A map of values passed in to satisfy the Reactor's expected
|
||||
inputs.
|
||||
* `context` - An arbitrary map that will be merged into the Reactor context
|
||||
and passed into each step.
|
||||
|
||||
## Options
|
||||
|
||||
#{Spark.Options.docs(@option_schema)}
|
||||
"""
|
||||
@doc spark_opts: [{4, @option_schema}]
|
||||
@spec run(t | module, inputs, context_arg, options) :: {:ok, any} | {:error, any} | {:halted, t}
|
||||
def run(reactor, inputs \\ %{}, context \\ %{}, options \\ [])
|
||||
|
||||
|
@ -152,4 +197,24 @@ defmodule Reactor do
|
|||
when is_reactor(reactor) and reactor.state in ~w[pending halted]a do
|
||||
Executor.run(reactor, inputs, context, options)
|
||||
end
|
||||
|
||||
def run(reactor, _inputs, _context, _options) do
|
||||
{:error,
|
||||
StateError.exception(
|
||||
reactor: reactor,
|
||||
state: reactor.state,
|
||||
expected: ~w[pending halted]a
|
||||
)}
|
||||
end
|
||||
|
||||
@doc "Raising version of `run/4`."
|
||||
@spec run!(t | module, inputs, context_arg, options) :: any | no_return
|
||||
def run!(reactor, inputs \\ %{}, context \\ %{}, options \\ [])
|
||||
|
||||
def run!(reactor, inputs, context, options) do
|
||||
case run(reactor, inputs, context, options) do
|
||||
{:ok, value} -> {:ok, value}
|
||||
{:error, reason} -> raise reason
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -22,7 +22,7 @@ defmodule Reactor.Builder do
|
|||
import Reactor, only: :macros
|
||||
import Reactor.Utils
|
||||
|
||||
@type step_options :: [async? | max_retries() | arguments_transform | context | ref]
|
||||
@type step_options :: [async? | max_retries | arguments_transform | context | ref]
|
||||
|
||||
@typedoc "Should the step be run asynchronously?"
|
||||
@type async? :: {:async?, boolean | (keyword -> boolean)}
|
||||
|
|
|
@ -9,9 +9,54 @@ defmodule Reactor.Builder.Step do
|
|||
import Reactor.Argument, only: :macros
|
||||
import Reactor.Utils
|
||||
|
||||
@option_schema [
|
||||
async?: [
|
||||
type: :boolean,
|
||||
default: true,
|
||||
required: false,
|
||||
doc: "Allow the step to be run asynchronously?"
|
||||
],
|
||||
max_retries: [
|
||||
type: {:or, [:non_neg_integer, {:literal, :infinity}]},
|
||||
default: 100,
|
||||
required: false,
|
||||
doc: "The maximum number of times the step can ask to be retried"
|
||||
],
|
||||
transform: [
|
||||
type: {:or, {:mfa_or_fun, 1}},
|
||||
required: false,
|
||||
doc: "A function which can modify all incoming arguments"
|
||||
],
|
||||
context: [
|
||||
type: :map,
|
||||
required: false,
|
||||
doc: "Context which will be merged with the reactor context when calling this step"
|
||||
],
|
||||
ref: [
|
||||
type: {:in, [:step_name, :make_ref]},
|
||||
required: false,
|
||||
default: :make_ref,
|
||||
doc: "What sort of step reference to generate"
|
||||
]
|
||||
]
|
||||
|
||||
@doc """
|
||||
Build and add a new step to a Reactor.
|
||||
|
||||
## Arguments
|
||||
|
||||
* `reactor` - An existing Reactor struct to add the step to.
|
||||
* `name` - The proposed name of the new step.
|
||||
* `impl` - A module implementing the `Reactor.Step` behaviour (or a tuple
|
||||
containing the module and options).
|
||||
* `arguments` - A list of `Reactor.Argument` structs or shorthand keyword
|
||||
lists.
|
||||
|
||||
## Options
|
||||
|
||||
#{Spark.Options.docs(@option_schema)}
|
||||
"""
|
||||
@doc spark_opts: [{5, @option_schema}]
|
||||
@spec add_step(
|
||||
Reactor.t(),
|
||||
any,
|
||||
|
@ -65,7 +110,21 @@ defmodule Reactor.Builder.Step do
|
|||
|
||||
You're most likely to use this when dynamically returning new steps from an
|
||||
existing step.
|
||||
|
||||
|
||||
## Arguments
|
||||
|
||||
* `name` - The name of the new step.
|
||||
* `impl` - A module implementing the `Reactor.Step` behaviour (or a tuple
|
||||
containing the module and options).
|
||||
* `arguments` - A list of `Reactor.Argument` structs or shorthand keyword
|
||||
lists.
|
||||
|
||||
## Options
|
||||
|
||||
#{Spark.Options.docs(@option_schema)}
|
||||
"""
|
||||
@doc spark_opts: [{5, @option_schema}]
|
||||
@spec new_step(any, Builder.impl(), [Builder.step_argument()], Builder.step_options()) ::
|
||||
{:ok, Step.t()} | {:error, any}
|
||||
def new_step(name, impl, arguments, options) do
|
||||
|
|
|
@ -2,8 +2,14 @@ defmodule Reactor.Step.AnonFn do
|
|||
@moduledoc """
|
||||
The built-in step for executing in-line DSL anonymous functions.
|
||||
|
||||
This step assumes that it is being called as per the
|
||||
`:spark_function_behaviour` semantics.
|
||||
## Options
|
||||
|
||||
* `run` - a one or two arity function or MFA which will be called as the run
|
||||
function of the step.
|
||||
* `compensate` - a one to three arity function or MFA which will be called as
|
||||
the compensate function of the step. Optional.
|
||||
* `undo` - a one to three arity function or MFA which will be called as the
|
||||
undo function of this step. Optional.
|
||||
"""
|
||||
|
||||
use Reactor.Step
|
||||
|
|
|
@ -5,13 +5,18 @@ defmodule Reactor.Step.ComposeWrapper do
|
|||
|
||||
Yes, this gets hairy, fast.
|
||||
|
||||
This is dynamically injected into steps by `Reactor.Step.Compose` - you
|
||||
probably don't want to use this unless you're sure what you're doing.
|
||||
|
||||
## Options
|
||||
|
||||
* `original` - the original value of the Step's `impl` key.
|
||||
* `prefix` - a list of values to be placed in the `name` before the original value.
|
||||
* `prefix` - a list of values to be placed in the `name` before the original
|
||||
value.
|
||||
|
||||
> #### Tip {: .tip}
|
||||
>
|
||||
> This is dynamically injected into steps by `Reactor.Step.Compose`.
|
||||
>
|
||||
> Most likely you will never need to use this step directly.
|
||||
"""
|
||||
|
||||
use Reactor.Step
|
||||
|
|
|
@ -2,8 +2,20 @@ defmodule Reactor.Step.Transform do
|
|||
@moduledoc """
|
||||
The built-in step for executing input and argument transformations.
|
||||
|
||||
This step assumes that it is being executed as per `:spark_function_behaviour`
|
||||
semantics.
|
||||
Expects a single argument named `value` which contains the value to be
|
||||
transformed.
|
||||
|
||||
## Options
|
||||
|
||||
* `fun` - a one or two arity function or MFA to use to modify the `value`
|
||||
argument.
|
||||
|
||||
> #### Tip {: .tip}
|
||||
>
|
||||
> This step is emitted by the builder when an argument needs to be transformed
|
||||
> before being passed into a step.
|
||||
>
|
||||
> Most likely you will never need to use this step directly.
|
||||
"""
|
||||
|
||||
alias Reactor.{Error.Invalid.MissingArgumentError, Error.Invalid.TransformError, Step}
|
||||
|
|
|
@ -4,6 +4,14 @@ defmodule Reactor.Step.TransformAll do
|
|||
|
||||
The returned map is used as the arguments to the step, instead of the step's
|
||||
defined arguments.
|
||||
|
||||
|
||||
> #### Tip {: .tip}
|
||||
>
|
||||
> This step will be emitted by the builder when a step wants to transform all
|
||||
> it's arguments.
|
||||
>
|
||||
> Most likely you will never need to use this step directly.
|
||||
"""
|
||||
|
||||
use Reactor.Step
|
||||
|
|
3
mix.exs
3
mix.exs
|
@ -38,9 +38,10 @@ defmodule Reactor.MixProject do
|
|||
end
|
||||
end,
|
||||
groups_for_modules: [
|
||||
DSL: ~r/^Reactor\.Dsl$/,
|
||||
Dsl: ~r/^Reactor\.Dsl.*/,
|
||||
Steps: ~r/^Reactor\.Step.*/,
|
||||
Middleware: ~r/^Reactor\.Middleware.*/,
|
||||
Errors: ~r/^Reactor\.Error.*/,
|
||||
Builder: ~r/^Reactor\.Builder.*/,
|
||||
Internals: ~r/^Reactor\..*/
|
||||
],
|
||||
|
|
Loading…
Reference in a new issue