# How to Use Worker Pools for High-Throughput Agent Workloads in Jido

> Boost Jido agent performance with worker pools. Optimize high-throughput workloads by reusing pre-initialized agents and avoid costly startup times.

- Repository: [agentjido/jido](https://github.com/agentjido/jido)
- Tags: how-to-guide
- Published: 2026-03-09

---

**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`](https://github.com/agentjido/jido/blob/main/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`](https://github.com/agentjido/jido/blob/main/lib/jido/agent/worker_pool.ex) (docs) |
| **`Jido.Config.Defaults`** | Supplies default timeouts for checkout and calls | [`lib/jido/config/defaults.ex`](https://github.com/agentjido/jido/blob/main/lib/jido/config/defaults.ex) |
| **`Jido.agent_pool_name/2`** | Generates unique module names for pool supervision | [`lib/jido.ex`](https://github.com/agentjido/jido/blob/main/lib/jido.ex) |
| **`Jido.AgentServer`** | The actual GenServer implementation running inside each pool worker | [`lib/jido/agent_server.ex`](https://github.com/agentjido/jido/blob/main/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:

```elixir
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 `:fifo` checkout order
- `worker_opts` – Additional options passed to `Jido.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:

```elixir
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:

```elixir
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`](https://github.com/agentjido/jido/blob/main/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:

```elixir
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/4` function 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:

```elixir
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`](https://github.com/agentjido/jido/blob/main/lib/jido/agent/worker_pool.ex) lines 199-207.

## Summary

- **Worker pools** in Jido use `Jido.Agent.WorkerPool` to maintain pre-initialized agents via Poolboy, eliminating expensive startup costs.
- **Configuration** happens through the `:agent_pools` option when starting your Jido instance, specifying pool size, overflow limits, and checkout strategy.
- **High-level APIs** include `with_agent/4` for complex transactions, `call/4` for synchronous requests, and `cast/4` for 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/2` provides 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.