Jido.Sensor behaviour (Jido v2.3.1)

Copy Markdown View Source

Defines the behaviour and metadata macro for Sensors in the Jido system.

A Sensor is a pure behaviour that transforms external events into Signals. Sensors are stateless modules that define how to initialize, handle events, and emit signals. Runtime execution is handled by Jido.Sensor.Runtime.

Usage

To define a new Sensor, use the Jido.Sensor behaviour in your module:

defmodule MySensor do
  use Jido.Sensor,
    name: "my_sensor",
    description: "Monitors a specific metric",
    schema: Zoi.object(%{
      metric: Zoi.string()
    })

  @impl true
  def init(config, _context) do
    {:ok, %{metric: config.metric, last_value: nil}}
  end

  @impl true
  def handle_event({:metric_update, value}, state) do
    signal = Jido.Signal.new!(%{
      source: "my_sensor",
      type: "metric.updated",
      data: %{value: value, previous: state.last_value}
    })
    {:ok, %{state | last_value: value}, [{:emit, signal}]}
  end
end

Callbacks

Implementing modules must define:

  • init/2: Initialize sensor state from config and context
  • handle_event/2: Process incoming events and emit signals

Optional callbacks:

  • terminate/2: Called when the sensor is shutting down (default: :ok)

Directives

Callbacks can return directives to request runtime actions:

  • {:schedule, interval} - Schedule next poll after interval ms
  • {:schedule, interval, payload} - Schedule with custom payload
  • {:emit, signal} - Emit a signal immediately

Sensor modules that need external subscriptions or connections should establish them in init/2 and clean them up in terminate/2.

Summary

Callbacks

Handle an incoming event and produce directives.

Initialize the sensor state.

Called when the sensor is shutting down.

Types

sensor_directive()

@type sensor_directive() ::
  {:schedule, pos_integer()}
  | {:schedule, pos_integer(), term()}
  | {:emit, Jido.Signal.t()}

Callbacks

handle_event(event, state)

@callback handle_event(event :: term(), state :: term()) ::
  {:ok, state :: term()}
  | {:ok, state :: term(), directives :: [sensor_directive()]}
  | {:error, reason :: term()}

Handle an incoming event and produce directives.

Called when the sensor receives an event from its connected source(s). Should return directives describing what actions to take.

Parameters

  • event - The incoming event (format depends on the source)
  • state - Current sensor state

Returns

  • {:ok, state} - Updated state with no directives
  • {:ok, state, directives} - Updated state with directives to execute
  • {:error, reason} - Event handling failed

Directives

  • {:emit, signal} - Emit a signal to the connected agent
  • {:schedule, interval_ms} - Schedule a :tick event after interval
  • {:schedule, interval_ms, event} - Schedule a custom event after interval

Example

def handle_event(:tick, state) do
  signal = Jido.Signal.new!(%{source: "/sensor/example", type: "example.tick"})
  {:ok, state, [{:emit, signal}, {:schedule, 1000}]}
end

init(config, context)

@callback init(config :: map(), context :: map()) ::
  {:ok, state :: term()}
  | {:ok, state :: term(), directives :: [sensor_directive()]}
  | {:error, reason :: term()}

Initialize the sensor state.

Called when the sensor is started. Receives the validated configuration and a context map containing runtime information.

Parameters

  • config - Validated configuration map (parsed against the sensor's schema)
  • context - Runtime context (e.g., sensor id, parent process info)

Returns

  • {:ok, state} - Initial state for the sensor
  • {:ok, state, directives} - Initial state with startup directives
  • {:error, reason} - Initialization failed

terminate(reason, state)

@callback terminate(reason :: term(), state :: term()) :: :ok

Called when the sensor is shutting down.

Use this to clean up any resources. The default implementation returns :ok.

Parameters

  • reason - The shutdown reason
  • state - Current sensor state

Returns

  • :ok - Shutdown complete