How to Use Worker Pools for High-Throughput Agent Workloads in Jido
Jido provides a Poolboy-based worker pool abstraction via Jido.Agent.WorkerPool that maintains pre-initialized agents for reuse, eliminating expensive startup costs during high-throughput scenarios.
The agentjido/jido repository ships with a robust worker pool implementation designed specifically for agent workloads. When an agent's initialization is expensive—such as loading machine learning models or establishing network connections—creating a new process per request creates unacceptable latency. Jido's worker pool solves this by keeping a set of warm Jido.AgentServer processes ready for immediate checkout.
Architecture Overview
Jido's pooling system consists of several coordinated components:
| Component | Role | Key Source |
|---|---|---|
Jido.Agent.WorkerPool |
Provides transaction-style API (with_agent/4, call/4, cast/4) and low-level checkout/3 / checkin/3 operations |
lib/jido/agent/worker_pool.ex |
| Pool Configuration | Declared via :agent_pools option with Poolboy settings (size, max_overflow, strategy) |
lib/jido/agent/worker_pool.ex (docs) |
Jido.Config.Defaults |
Supplies default timeouts for checkout and calls | lib/jido/config/defaults.ex |
Jido.agent_pool_name/2 |
Generates unique module names for pool supervision | lib/jido.ex |
Jido.AgentServer |
The actual GenServer implementation running inside each pool worker | lib/jido/agent_server.ex |
When a Jido instance starts, the supervisor calls WorkerPool.build_pool_child_spec/4 to create Poolboy child specs for every pool declared in :agent_pools. Each worker in the pool is an instance of Jido.AgentServer initialized with the specified agent module.
Configuring Worker Pools
Define pools in your application supervision tree using the :agent_pools option:
children = [
{Jido,
name: MyApp.Jido,
agent_pools: [
# High-throughput search pool: 8 permanent workers, 4 overflow, LIFO checkout
{:fast_search, MyApp.Agents.SearchAgent,
size: 8, max_overflow: 4, strategy: :lifo},
# Planner pool: 4 workers with FIFO ordering
{:planner, MyApp.Agents.PlannerAgent,
size: 4, strategy: :fifo}
]}
]
Configuration parameters:
size– Number of agents kept permanently alive (default: 5)max_overflow– Temporary workers created when pool is exhausted (default: 0)strategy–:lifo(default) or:fifocheckout orderworker_opts– Additional options passed toJido.AgentServer.start_link/1
Default timeouts are defined in Jido.Config.Defaults via worker_pool_checkout_timeout_ms/0 and worker_pool_call_timeout_ms/0, but you can override these per-call using the :timeout (checkout) or :call_timeout (signal) options.
Using the Pool API
The Jido.Agent.WorkerPool module provides three high-level patterns for executing work against pooled agents.
Transaction-Style Execution with with_agent/4
Use with_agent/4 when you need to execute multiple operations against the same agent or require complex logic:
defmodule MyApp.BatchProcessor do
@jido MyApp.Jido
@pool :planner
def process_batch(batch) do
Jido.Agent.WorkerPool.with_agent(@jido, @pool, fn pid ->
Enum.each(batch, fn item ->
# Reuse the same checked-out agent for multiple signals
Jido.AgentServer.call(pid, {:plan, item})
end)
end)
end
end
The with_agent/4 function guarantees check-in even if the supplied function raises an exception, as it runs inside :poolboy.transaction/3.
Synchronous Calls with call/4
For single-shot synchronous operations, use call/4 which handles checkout, signal delivery, and check-in automatically:
defmodule MyApp.Search do
@jido MyApp.Jido
@pool :fast_search
def search(query) do
signal = {:search, query}
# Automatically checks out agent, sends signal, waits for reply, checks in
{:ok, results} = Jido.Agent.WorkerPool.call(@jido, @pool, signal)
results
end
end
This corresponds to the implementation in lib/jido/agent/worker_pool.ex lines 101-129.
Asynchronous Casts with cast/4
For fire-and-forget operations where you don't need a response:
defmodule MyApp.Notifications do
@jido MyApp.Jido
@pool :fast_search
def notify(event) do
# Checks out worker, sends async signal, immediately checks in
Jido.Agent.WorkerPool.cast(@jido, @pool, {:notify, event})
:ok
end
end
The cast/4 function checks out the worker, sends the asynchronous signal, and immediately checks the worker back in, as implemented in lines 130-152 of the worker pool module.
Error Handling and Guarantees
Jido's worker pools provide several safety guarantees for production workloads:
- Supervised workers: Each agent process is supervised by the top-level Jido supervisor. If a worker crashes, Poolboy discards the crashed process and spawns a fresh replacement.
- State persistence: Agent state persists across checkouts unless the worker crashes. For request-specific isolation, pass request data via signals rather than storing it in the agent's internal state.
- Guaranteed check-in: The
with_agent/4function ensures the agent is returned to the pool even if the supplied function raises an exception, preventing pool exhaustion due to leaked workers.
Monitoring Pool Status
For debugging and metrics collection, query the current state of any pool:
status = Jido.Agent.WorkerPool.status(MyApp.Jido, :fast_search)
IO.inspect(status)
# => %{state: :ready, available: 8, overflow: 0, checked_out: 0}
The status/2 function forwards to :poolboy.status/1 and returns a map showing available workers, overflow count, and checked-out count. This is implemented in lib/jido/agent/worker_pool.ex lines 199-207.
Summary
- Worker pools in Jido use
Jido.Agent.WorkerPoolto maintain pre-initialized agents via Poolboy, eliminating expensive startup costs. - Configuration happens through the
:agent_poolsoption when starting your Jido instance, specifying pool size, overflow limits, and checkout strategy. - High-level APIs include
with_agent/4for complex transactions,call/4for synchronous requests, andcast/4for asynchronous fire-and-forget operations. - Safety guarantees ensure crashed workers are replaced and agents are always returned to the pool, even when errors occur.
- Monitoring via
status/2provides visibility into pool utilization for capacity planning.
Frequently Asked Questions
What is the difference between call/4 and with_agent/4 in Jido worker pools?
call/4 is optimized for single-shot synchronous operations—it checks out an agent, sends one signal, waits for the response, and immediately returns the worker to the pool. with_agent/4 provides a transaction-style API where you receive the raw pid of a checked-out agent and can execute multiple operations or complex logic before the worker is automatically returned to the pool when your function completes or raises an exception.
How does Jido handle crashed workers in a pool?
Each worker in a Jido pool is supervised by the top-level Jido supervisor. If a worker process crashes during execution, Poolboy detects the crash, discards the failed process, and spawns a fresh replacement worker. This ensures that your pool maintains the configured capacity without manual intervention, though any state stored in the crashed worker is lost.
Can I customize timeouts for worker checkout and signal execution?
Yes. Jido defines default timeouts in Jido.Config.Defaults via worker_pool_checkout_timeout_ms/0 and worker_pool_call_timeout_ms/0. You can override these per-call by passing the :timeout option for checkout duration or the :call_timeout option for signal execution duration to call/4, cast/4, or with_agent/4.
What monitoring capabilities are available for Jido worker pools?
Jido exposes pool statistics through Jido.Agent.WorkerPool.status/2, which returns a map containing the pool state (:ready), number of available workers, overflow count, and currently checked-out workers. This function interfaces directly with :poolboy.status/1 and is useful for debugging connection leaks, capacity planning, and monitoring pool utilization in production environments.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →