Jido.Exec (Jido v1.1.0-rc.2)

View Source

Exec provides a robust set of methods for executing Actions (Jido.Action).

This module offers functionality to:

  • Run actions synchronously or asynchronously
  • Manage timeouts and retries
  • Cancel running actions
  • Normalize and validate input parameters and context
  • Emit telemetry events for monitoring and debugging

Execs are defined as modules (Actions) that implement specific callbacks, allowing for a standardized way of defining and executing complex actions across a distributed system.

Features

  • Synchronous and asynchronous action execution
  • Automatic retries with exponential backoff
  • Timeout handling for long-running actions
  • Parameter and context normalization
  • Comprehensive error handling and reporting
  • Telemetry integration for monitoring and tracing
  • Cancellation of running actions

Usage

Execs are executed using the run/4 or run_async/4 functions:

Jido.Exec.run(MyAction, %{param1: "value"}, %{context_key: "context_value"})

See Jido.Action for how to define an Action.

For asynchronous execution:

async_ref = Jido.Exec.run_async(MyAction, params, context)
# ... do other work ...
result = Jido.Exec.await(async_ref)

Summary

Functions

Waits for the result of an asynchronous Action execution.

Cancels a running asynchronous Action execution.

Executes a Action synchronously with the given parameters and context.

Executes a Action asynchronously with the given parameters and context.

Types

action()

@type action() :: module()

async_ref()

@type async_ref() :: %{ref: reference(), pid: pid()}

context()

@type context() :: map()

params()

@type params() :: map()

run_opts()

@type run_opts() :: [{:timeout, non_neg_integer()}]

Functions

await(map, timeout \\ 5000)

@spec await(async_ref(), timeout()) :: {:ok, map()} | {:error, Jido.Error.t()}

Waits for the result of an asynchronous Action execution.

Parameters

  • async_ref: The reference returned by run_async/4.
  • timeout: Maximum time (in ms) to wait for the result (default: 5000).

Returns

  • {:ok, result} if the Action executes successfully.
  • {:error, reason} if an error occurs during execution or if the action times out.

Examples

iex> async_ref = Jido.Exec.run_async(MyAction, %{input: "value"})
iex> Jido.Exec.await(async_ref, 10_000)
{:ok, %{result: "processed value"}}

iex> async_ref = Jido.Exec.run_async(SlowAction, %{input: "value"})
iex> Jido.Exec.await(async_ref, 100)
{:error, %Jido.Error{type: :timeout, message: "Async action timed out after 100ms"}}

cancel(pid)

@spec cancel(async_ref() | pid()) :: :ok | {:error, Jido.Error.t()}

Cancels a running asynchronous Action execution.

Parameters

  • async_ref: The reference returned by run_async/4, or just the PID of the process to cancel.

Returns

  • :ok if the cancellation was successful.
  • {:error, reason} if the cancellation failed or the input was invalid.

Examples

iex> async_ref = Jido.Exec.run_async(LongRunningAction, %{input: "value"})
iex> Jido.Exec.cancel(async_ref)
:ok

iex> Jido.Exec.cancel("invalid")
{:error, %Jido.Error{type: :invalid_async_ref, message: "Invalid async ref for cancellation"}}

dbug(_, _ \\ [])

(macro)

error(_, _ \\ [])

(macro)

run(action, params \\ %{}, context \\ %{}, opts \\ [])

@spec run(action(), params(), context(), run_opts()) ::
  {:ok, map()} | {:error, Jido.Error.t()}

Executes a Action synchronously with the given parameters and context.

Parameters

  • action: The module implementing the Action behavior.
  • params: A map of input parameters for the Action.
  • context: A map providing additional context for the Action execution.
  • opts: Options controlling the execution:
    • :timeout - Maximum time (in ms) allowed for the Action to complete (default: 5000).
    • :max_retries - Maximum number of retry attempts (default: 1).
    • :backoff - Initial backoff time in milliseconds, doubles with each retry (default: 250).
    • :log_level - Override the global Logger level for this specific action. Accepts [:error, :info, :debug, :emergency, :alert, :critical, :warning, :notice].

Action Metadata in Context

The action's metadata (name, description, category, tags, version, etc.) is made available to the action's run/2 function via the context parameter under the :action_metadata key. This allows actions to access their own metadata when needed.

Returns

  • {:ok, result} if the Action executes successfully.
  • {:error, reason} if an error occurs during execution.

Examples

iex> Jido.Exec.run(MyAction, %{input: "value"}, %{user_id: 123})
{:ok, %{result: "processed value"}}

iex> Jido.Exec.run(MyAction, %{invalid: "input"}, %{}, timeout: 1000)
{:error, %Jido.Error{type: :validation_error, message: "Invalid input"}}

iex> Jido.Exec.run(MyAction, %{input: "value"}, %{}, log_level: :debug)
{:ok, %{result: "processed value"}}

# Access action metadata in the action:
# defmodule MyAction do
#   use Jido.Action,
#     name: "my_action",
#     description: "Example action",
#     vsn: "1.0.0"
#
#   def run(_params, context) do
#     metadata = context.action_metadata
#     {:ok, %{name: metadata.name, version: metadata.vsn}}
#   end
# end

run_async(action, params \\ %{}, context \\ %{}, opts \\ [])

@spec run_async(action(), params(), context(), run_opts()) :: async_ref()

Executes a Action asynchronously with the given parameters and context.

This function immediately returns a reference that can be used to await the result or cancel the action.

Note: This approach integrates with OTP by spawning tasks under a Task.Supervisor. Make sure {Task.Supervisor, name: Jido.Exec.TaskSupervisor} is part of your supervision tree.

Parameters

  • action: The module implementing the Action behavior.
  • params: A map of input parameters for the Action.
  • context: A map providing additional context for the Action execution.
  • opts: Options controlling the execution (same as run/4).

Returns

An async_ref map containing:

  • :ref - A unique reference for this async action.
  • :pid - The PID of the process executing the Action.

Examples

iex> async_ref = Jido.Exec.run_async(MyAction, %{input: "value"}, %{user_id: 123})
%{ref: #Reference<0.1234.5678>, pid: #PID<0.234.0>}

iex> result = Jido.Exec.await(async_ref)
{:ok, %{result: "processed value"}}