I want to perform some post-processing after the c...
# ask-ai
w
I want to perform some post-processing after the call has finished. Like e.g. summarizing the call, .... But this process can take some time, where should i locate this and how can i trigger it? I am using the Python Agent SDK
t
Thanks for reaching out, Lukas. I'm an AI assistant and I'm here to help. Give me a moment while I research this topic.
Thanks — I’m responding about where to place and how to trigger long-running post‑processing (e.g., call summarization) when using the Python Agent SDK. Use a shutdown callback on the job context. Register an async function with
ctx.add_shutdown_callback()
inside your agent entrypoint so it runs after the room disconnects but before the worker shuts down. Start the long task in the background (e.g., with
asyncio.create_task
) so it won’t block shutdown housekeeping. Minimal example:
Copy code
@server.rtc_session()
async def entrypoint(ctx: JobContext):
    session = AgentSession(...)
    await session.start(agent=agent, room=ctx.room)
    await ctx.connect()

    async def on_shutdown():
        # run long-running post-processing in background
        asyncio.create_task(summarize_call(session, ctx.room))

    ctx.add_shutdown_callback(on_shutdown)
Notes and best practices: • Place the callback in the entrypoint where
ctx
is available. • Access transcripts/metrics from
session
inside your callback before it’s torn down. • Wrap background work in try/except and clean up any external clients when finished. • Use background tasks so the agent cleanup isn’t blocked. If you want, tell me: • how you store transcripts (in-session or external), and • whether the summarization must finish before other downstream steps — I’ll suggest patterns for guaranteed completion vs. fire-and-forget. Sources: Collect recording consent with tasks | LiveKit docs
w
the transcript is stored in te session and i think it could be a fire and forget. At the moment i get an error like this: {"level": "ERROR", "name": "livekit.agents", "message": "process did not exit in time, killing process", "pid": 3868676, "job_id": "AJ_DXvdpggJBQ7R", "room_id": "RM_27Ap64iKnXZR", "timestamp": "2026-01-02T083933.424831+00:00"} How can i prevent this?
t
Thanks — I’m responding about preventing the "process did not exit in time, killing process" error when you run a fire‑and‑forget summarization stored in the session. What’s happening • The worker expects the process to exit quickly after the agent session ends. Long-running work that blocks shutdown causes that timeout and the error. What to do (concise steps) 1. Register a shutdown callback in your entrypoint with
ctx.add_shutdown_callback()
so post‑call work runs after disconnect. 2. Start the summarization in the background inside that callback — do NOT
await
it. Use
asyncio.create_task()
so the callback returns immediately. Example pattern
Copy code
async def on_shutdown():
    # non-blocking: fire-and-forget
    asyncio.create_task(summarize_call(session.transcript))

ctx.add_shutdown_callback(on_shutdown)
1. Keep the shutdown callback itself short and non-blocking. Never
await
the long task there. 2. Make the background task resilient: ◦ Catch
asyncio.CancelledError
to handle mid-shutdown termination. ◦ Save partial results or enqueue work to an external queue if you need retries. ◦ Close any external clients only after starting the background task, or use separate clients inside the background task so shutdown cleanup doesn’t cancel it prematurely. 1. If you must guarantee completion, switch from fire‑and‑forget to a reliable handoff: push the transcript to a queue (e.g., SQS, Pub/Sub, or a webhook) in the shutdown callback and process it externally — this avoids process timeout entirely. If you want, share a short snippet of your current shutdown handler (or confirm you’re already using
ctx.add_shutdown_callback()
), and I’ll point out the exact change you need. Sources: How to detect and handle silence during calls | examples/frontdesk | livekit/livekit_composite | DeepWiki | Collect recording consent with tasks | LiveKit docs | examples/voice_agents | livekit/livekit_composite | DeepWiki | STT Metrics | LiveKit docs
s
@wonderful-wolf-51568, you can listen to the webhook of the room ended in any other service and do what you want there, so you do not keep the agent busy
t
Acknowledged — you can safely offload long-running post‑call work to a separate service via a room-finished webhook so the agent doesn’t stay busy. Quick guidance to implement this (concise): • Subscribe to the room finished webhook (room_finished / room.ended) in your backend. This fires when the JobContext/room ends. • In the webhook handler, fetch the transcript from wherever you persist it (since session data lives with the agent, you must persist the transcript during the call or include a location/ID in the webhook payload). • Perform summarization or other heavy work in that service (LLM calls, uploads, DB writes). This is fully decoupled from the agent and avoids shutdown timeouts. If you prefer keeping work in the agent: • Use
ctx.add_shutdown_callback()
in the entrypoint to start a background task with
asyncio.create_task()
so the callback returns immediately. • Ensure the shutdown callback does not
await
long tasks. • Consider increasing the agent process grace period with
--shutdown-grace-period=<seconds>
if you need more time. • For guaranteed processing, push the transcript to a queue (SQS/PubSub) in the shutdown callback and process it externally. If you share how you currently persist transcripts (in-session only, or also saved to storage) I’ll give an exact webhook handler pattern or the precise change to your shutdown callback to avoid the timeout. Sources: Collect recording consent with tasks | LiveKit docs | How to detect when an agent has finished speaking | server-sdk-js | livekit/livekit_composite | DeepWiki