Signal System Overview
Introduction
Signals are the messaging system in Jido, serving as the nervous system of your agent-based applications. Based on the CloudEvents specification (v1.0.2), Signals provide a standardized way to represent events, commands, and state changes across your distributed system.
> ### Learn with Livebook {: .tip}
>
> This guide is available as a Livebook. The examples below can be run interactively.
>
Mix.install([
{:jido, "~> 0.1.0"}
])
Core Concepts
Signals in Jido provide:
- Standardized event structure (CloudEvents v1.0.2 compatible)
- Rich metadata and context tracking
- Built-in instruction handling
- Flexible dispatch configuration
- Automatic serialization
Basic Signal Structure
A Signal contains both CloudEvents standard fields and Jido-specific extensions:
# Create a basic signal
{:ok, signal} = Jido.Signal.new(%{
type: "user.created",
source: "/auth/registration",
data: %{
user_id: "123",
email: "user@example.com"
}
})
# Inspect the signal structure
IO.inspect(signal, label: "Basic Signal")
CloudEvents Standard Fields
Every Signal includes these CloudEvents fields:
-
specversion
: Always “1.0.2” -
id
: Unique identifier (UUID v4) -
source
: Origin of the event (“/service/component”) -
type
: Classification of the event (“domain.entity.action”) -
subject
: Specific subject (optional) -
time
: ISO 8601 timestamp -
datacontenttype
: Media type of data -
dataschema
: Schema definition URL -
data
: Event payload
Signal Types and Naming
Signal types use a hierarchical dot notation:
..[.]
Examples:
# Standard event
{:ok, user_updated} = Jido.Signal.new(%{
type: "user.profile.updated",
source: "/users",
data: %{user_id: "123", changes: %{name: "New Name"}}
})
# Event with qualifier
{:ok, payment_failed} = Jido.Signal.new(%{
type: "order.payment.processed.failed",
source: "/payments",
data: %{order_id: "456", reason: "insufficient_funds"}
})
Best Practices for Signal Types
- Use lowercase with dots
- Keep segments meaningful
- Order from general to specific
- Include qualifiers when needed
Jido Extensions
Beyond CloudEvents, Signals include Jido-specific fields:
Instructions
Instructions tell agents what actions to take:
{:ok, task_signal} = Jido.Signal.new(%{
type: "task.assigned",
source: "/workflow",
data: %{task_id: "789"},
jido_instructions: [
ValidateTask,
{AssignTask, %{worker: "agent_1"}},
NotifyAssignment
]
})
Dispatch Configuration
Control how signal responses are delivered:
# Single dispatch target
{:ok, metric_signal} = Jido.Signal.new(%{
type: "metrics.collected",
source: "/monitoring",
data: %{cpu: 80, memory: 70},
jido_dispatch: {:pubsub, [topic: "metrics"]}
})
# Multiple dispatch targets
{:ok, audit_signal} = Jido.Signal.new(%{
type: "user.permission.changed",
source: "/auth",
data: %{user_id: "123", role: "admin"},
jido_dispatch: [
{:pubsub, [topic: "audit.events"]},
{:logger, [level: :info]},
{:bus, [target: :audit_bus]}
]
})
Built-in Dispatch Adapters
Jido provides several dispatch adapters out of the box:
-
:pid
- Direct delivery to a specific process -
:bus
- Delivery to an event bus -
:named
- Delivery to a named process -
:pubsub
- Delivery via Phoenix.PubSub -
:logger
- Log signals using Logger -
:console
- Print signals to console -
:noop
- No-op adapter for testing
Example: Using Different Adapters
# Direct process delivery
pid_config = {:pid, [
target: self(),
delivery_mode: :async
]}
# Event bus delivery
bus_config = {:bus, [
target: :my_bus,
stream: "default"
]}
# PubSub broadcast
pubsub_config = {:pubsub, [
target: :my_app_pubsub,
topic: "events"
]}
# Create and dispatch a signal
{:ok, signal} = Jido.Signal.new(%{
type: "example.created",
source: "/demo",
data: %{id: "123"},
jido_dispatch: [pid_config, bus_config, pubsub_config]
})
Error Handling
Signals include built-in error handling for various scenarios:
# Handle dispatch failures
case Jido.Signal.Dispatch.dispatch(signal, dispatch_config) do
:ok ->
IO.puts("Signal dispatched successfully")
{:error, :process_not_found} ->
IO.puts("Target process not found")
{:error, :bus_not_found} ->
IO.puts("Target bus not found")
{:error, reason} ->
IO.puts("Dispatch failed: #{inspect(reason)}")
end
Custom Dispatch Adapters
You can create custom adapters by implementing the Jido.Signal.Dispatch.Adapter
behaviour:
defmodule MyApp.CustomAdapter do
@behaviour Jido.Signal.Dispatch.Adapter
@impl true
def validate_opts(opts) do
# Validate configuration options
{:ok, opts}
end
@impl true
def deliver(signal, opts) do
# Custom delivery logic
:ok
end
end
# Use custom adapter
custom_config = {MyApp.CustomAdapter, [
custom_option: "value"
]}
Next Steps
Now that you understand the basics of Signals in Jido, explore these related guides:
See Also
- CloudEvents Specification
-
Jido.Signal
- Core Signal module -
Jido.Signal.Dispatch
- Signal dispatch system -
Jido.Signal.Dispatch.Adapter
- Adapter behaviour