The wire shape between a %Statifier.Effect.Invoke{} and the args map
an invoke-handler Oban job stores.
Oban args live as JSON, so this module owns the (de)serialization of
the one effect an invoke job carries, plus the scope it was enqueued
under and the handler module whose run/1 the worker calls back into.
The rules are StatifierOban.Timer.JobArgs's, applied to the invoke
effect:
- Every deterministic field rides as an explicit JSON value: the dedup
pair (
scope,invoke_id) at the top level - Oban's uniquenesskeysread args at the top level - and the effect's position row data (state_index,invoke_index,macrostep,microstep,round) beside it, self-describing in the store during an incident.invoke_idis the deterministic%MachineState{}counter st-ADR-0008 (as amended) blesses as the idempotency key; scoping is mandatory because that counter restarts per chart run. - The two host-opaque fields,
paramsandcontent, are arbitrary terms with no JSON shape, so they ride as tagged:erlang.term_to_binary/1payloads (StatifierOban.OpaqueTerm) and come back byte-identical. handleris the module name of theStatifierOban.Invoke.Handlerimplementation, written from a validated module at enqueue time and resolved back by the worker - a resolution failure there is deploy-shaped (the module was renamed or removed after the job was stored) and retries, exactly like the timer worker's delivery module.
to_invoke/1 is the exact inverse of from_invoke/3 for every
%Statifier.Effect.Invoke{} the base handler enqueues: what the job
carries is enough to hand the handler's run/1 the same effect the
planning callback saw.
Summary
Functions
Builds the args map for an invoke job from the scope, the handler module, and the effect.
Rebuilds the scope, the handler module name, and the
%Statifier.Effect.Invoke{} from a job's args.
Types
Functions
@spec from_invoke(String.t(), module(), Statifier.Effect.Invoke.t()) :: args()
Builds the args map for an invoke job from the scope, the handler module, and the effect.
The caller (StatifierOban.Invoke.Handler.perform_start/3) has already
validated the scope; this function only lays fields out on the wire.
@spec to_invoke(args()) :: {:ok, String.t(), String.t(), Statifier.Effect.Invoke.t()} | {:error, decode_error()}
Rebuilds the scope, the handler module name, and the
%Statifier.Effect.Invoke{} from a job's args.
The handler comes back as the stored string, not a resolved module: resolution is the worker's call, because an unresolvable name is a retryable environment fact where every error here is a fact about the row. Returns a typed error rather than raising: an undecodable job is a fact about the row, and the worker decides what to do with it.