The wire shape between a %Statifier.Effect.SendDelayed{} and the args
map an Oban job stores.
Oban args live as JSON, so this module owns the (de)serialization of the one effect a timer job carries, plus the scope it was scheduled under. Two rules shape it:
- Every deterministic field rides as an explicit JSON value: the dedup
pair (
scope,ordinal) at the top level - Oban's uniquenesskeysread args at the top level - and the row data ADR-0059 (statifier-ex) keeps beside the key (send_id,macrostep,microstep,round,c_index,owner), self-describing in the store during an incident. - The two host-opaque fields,
dataandcaller_context, are arbitrary terms with no JSON shape, so they ride as tagged:erlang.term_to_binary/1payloads (StatifierOban.OpaqueTerm) and come back byte-identical.caller_contextstays row data, never a key component (st-ADR-0063 decision 6). Decoding uses:safe, so a payload naming an atom the reading node has never seen decodes to a typed error rather than minting atoms.
to_effect/1 is the exact inverse of from_effect/2 for every
%SendDelayed{} the scheduler accepts: what the fired job carries is
enough to rebuild the event and its position, per ADR-0054's
correlation rule - position is read off the stored effect, never
recomputed at delivery.
Summary
Functions
Builds the args map for a timer job from the scope and the effect.
Rebuilds the scope and the %SendDelayed{} from a job's args.
Types
Functions
@spec from_effect(String.t(), Statifier.Effect.SendDelayed.t()) :: args()
Builds the args map for a timer job from the scope and the effect.
The caller has already validated the scope and ordinal via
StatifierOban.Timer.Key.dedup_key/2; this function only lays fields
out on the wire.
@spec to_effect(args()) :: {:ok, String.t(), Statifier.Effect.SendDelayed.t()} | {:error, decode_error()}
Rebuilds the scope and the %SendDelayed{} from a job's args.
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.