backend_pool
backend_pool
¶
Backend pool — per-instrument backend instance management.
The baton dispatches sheets to execution, each requiring a Backend instance for its assigned instrument. The BackendPool manages these instances:
- CLI instruments get one Backend per concurrent sheet (subprocess isolation — each sheet runs in its own process).
- HTTP instruments share a singleton Backend (httpx handles connection pooling and concurrency internally).
The pool tracks how many instances are in-flight per instrument, which the baton uses to enforce per-instrument concurrency limits.
Design decisions:
- Lazy creation — Backend instances are created on first acquire, not upfront. This avoids spawning processes for instruments that aren't used by any sheet in the current job.
- CLI reuse — Released CLI backends go back into a free list. The next acquire for the same instrument reuses an existing instance rather than creating a new one. This avoids repeated subprocess setup for sequential sheets on the same instrument.
- Lock-free acquire for HTTP — HTTP singletons are created once and returned on every acquire. No release needed (the pool tracks them but doesn't recycle them).
- Graceful close —
close_all()closes every Backend instance (callsbackend.close()). Called by the baton at job completion or cancellation.
See: docs/plans/2026-03-26-baton-design.md — BackendPool section.
Classes¶
BackendPool
¶
Manages Backend instances for per-sheet execution.
The baton acquires a backend before dispatching a sheet and releases it after the sheet completes (or fails). The pool enforces per-instrument concurrency by tracking in-flight instances.
Usage::
pool = BackendPool(registry)
# Dispatch a sheet
backend = await pool.acquire("claude-code", working_directory=ws)
try:
result = await backend.execute(prompt)
finally:
await pool.release("claude-code", backend)
# Job done
await pool.close_all()
Source code in src/marianne/daemon/baton/backend_pool.py
Functions¶
acquire
async
¶
Acquire a Backend instance for an instrument.
For CLI instruments: returns a free instance if available, otherwise creates a new one. For HTTP instruments: returns the shared singleton (creating it on first call).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
instrument_name
|
str
|
Name of the instrument (from registry). |
required |
model
|
str | None
|
Optional model override for this execution. |
None
|
working_directory
|
Path | None
|
Working directory for the backend. |
None
|
Returns:
| Type | Description |
|---|---|
Backend
|
A Backend instance ready for execution. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the instrument is not registered. |
RuntimeError
|
If the pool has been closed. |
Source code in src/marianne/daemon/baton/backend_pool.py
release
async
¶
Release a Backend instance back to the pool.
For CLI instruments: the backend goes back to the free list for reuse. For HTTP instruments: no-op (the singleton stays active).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
instrument_name
|
str
|
The instrument name used in |
required |
backend
|
Backend
|
The Backend instance to release. |
required |
Source code in src/marianne/daemon/baton/backend_pool.py
in_flight_count
¶
How many backends are currently acquired for this instrument.
Used by the baton's dispatch logic to enforce per-instrument concurrency limits.
Source code in src/marianne/daemon/baton/backend_pool.py
total_in_flight
¶
close_all
async
¶
Close all Backend instances and mark the pool as closed.
Called at job completion, cancellation, or conductor shutdown.
After this call, acquire() raises RuntimeError.