Pass structured results between workflow steps.
Results are stored on the step's workflow_nodes row — never in
oban_jobs.meta. Because the engine owns that table, writing a result never
contends with Oban's own writes (the data race the old meta-based approach
had). The public API is unchanged.
Storing a result (upstream worker)
Return {:ok, result} from perform_workflow/1; Baton.Worker
persists it automatically.
def perform_workflow(%Oban.Job{args: %{"api_key" => key}}) do
{:ok, %{token: fetch_token(key)}}
endReading a result (downstream worker)
case Results.get_result(job, :fetch_token) do
{:ok, %{"token" => token}} -> ...
{:error, reason} -> {:error, reason}
endReading all upstream results
results = Results.get_all_results(job)
# => %{"fetch_token" => %{"token" => "..."}, ...}
Summary
Functions
Results from all of this job's dependencies that have stored one, keyed by step name. Steps still running, or with no result, are omitted.
The result this job stored on a previous attempt — the idempotency guard.
Fetch the stored result of a specific upstream step.
Persist a result for the current job. Called automatically by the worker on
{:ok, result}. Returns :ok or {:error, reason}.
Functions
@spec get_all_results(Oban.Job.t()) :: %{required(String.t()) => term()}
Results from all of this job's dependencies that have stored one, keyed by step name. Steps still running, or with no result, are omitted.
@spec get_own_result(Oban.Job.t()) :: {:ok, term()} | {:error, :no_result}
The result this job stored on a previous attempt — the idempotency guard.
Returns {:ok, value} if a result was stored, {:error, :no_result}
otherwise. Jobs without a workflow node return {:error, :no_result}.
@spec get_result(Oban.Job.t(), atom() | String.t()) :: {:ok, term()} | {:error, :no_workflow | :not_a_dep | :not_found | :no_result}
Fetch the stored result of a specific upstream step.
Errors:
:no_workflow— this job has no workflow node:not_a_dep— the named step isn't a declared dependency of this job:not_found— no such step in this workflow:no_result— the step exists but hasn't stored a result yet
@spec store_result(Oban.Job.t(), term()) :: :ok | {:error, term()}
Persist a result for the current job. Called automatically by the worker on
{:ok, result}. Returns :ok or {:error, reason}.