I have a voice agent (agents 1.5.17, Python) that needs to read a small
amount of candidate context from MongoDB Atlas at the start of each call.
I want this DB connection to be warm before a job starts, the same way prewarm_fnc lets me pre-load VAD/TTS models.
What’s happening instead
The first DB query inside the entrypoint takes 6-11 seconds, even though the
query itself returns in ~150ms once the connection is established. This
latency is fully visible to the end user as dead air at call start.
Is there a supported way to:
1. Run async setup (e.g. opening a DB connection pool) once per ‘worker process’, persisted across multiple jobs handled by the same `num_idle_processes` warm process — rather than once per job?
2. Or, is `prewarm_fnc` intentionally sync-only, and the expected pattern is to keep long-lived async resources alive at the module level across jobs within the same process (bypassing the “bind to current running loop” pattern some async DB drivers recommend)?
@jitendra, prewarm runs before the process has an event loop: the proc client calls your prewarm_fnc in its initialize step, then creates the asyncio loop only afterward [ agents ipc/proc_client.py ]. That’s why an async client opened there binds to the wrong loop. So yes, it’s effectively sync for this.
What solves it: a warm process runs every job it handles on a single event loop created once per process [ same file, run() makes one new_event_loop() ], and ctx.proc.userdata is a process-lifetime dict [ agents job.py ]. So lazy-init the client on the first job and cache it there; later jobs in that process reuse it on the same loop, so you pay the 6-11s connect once per process, not per call, and you don’t break the driver’s bind-to-running-loop rule.
async def entrypoint(ctx: JobContext):
if "mongo" not in ctx.proc.userdata:
client = AsyncIOMotorClient(MONGO_URI)
await client.admin.command("ping") # pay the connect once, on the job loop
ctx.proc.userdata["mongo"] = client
db = ctx.proc.userdata["mongo"]["yourdb"]
# ~150ms queries from here
Keep enough num_idle_processes warm that a ready process is usually waiting [ agents worker.py ]; the only call that still pays the connect is the first one each fresh process handles.