cool-lizard-26153
04/20/2026, 7:37 AMtall-airline-16756
04/20/2026, 7:37 AMtall-airline-16756
04/20/2026, 7:38 AMWS_FULL).
• It stops accepting new job launches and waits for in-flight launches to finish, then waits for running jobs to complete up to the configured drain_timeout.
• drain_timeout defaults to 1800s (30 minutes) and can be configured when starting the agent.
Practical tips:
• Start the agent in production/graceful mode (e.g., uv run agent.py start for Python or tsc && node agent.js start for Node) so shutdown handling is enabled.
• Ensure SIGTERM is delivered to the agent process (avoid wrapper scripts that swallow signals; if using a wrapper, use exec ... so the agent receives the signal).
• Monitor agent logs for "draining worker" to verify drain started.
If you’d like, tell me which runtime (Python or Node) and how you deploy (Kubernetes manifest, Helm, or another tool) and I’ll provide exact command examples and suggested drain_timeout placement for your setup.
Sources: Deployment reliability on LiveKit Cloud | LiveKit | Server startup modes | LiveKit Documentation | Job lifecycle | LiveKit Documentation | Deployment reliability on LiveKit Cloud | LiveKit, with interactive elementscool-lizard-26153
04/20/2026, 7:39 AMtall-airline-16756
04/20/2026, 7:39 AMuv run agent.py start).
• Ensure the agent process is PID 1 in the container (no signal-swallowing wrappers) or use exec in your entrypoint so SIGTERM reaches it.
• Configure drain_timeout to the maximum time you want pods to wait for active jobs to finish (defaults to 1800s).
Recommended Kubernetes Deployment snippet (adjust image, names, envs)
apiVersion: apps/v1
kind: Deployment
metadata:
name: livekit-agent
spec:
replicas: 3
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
maxSurge: 1
template:
metadata:
labels:
app: livekit-agent
spec:
terminationGracePeriodSeconds: 2000 # >= drain_timeout + buffer
containers:
- name: agent
image: your-registry/livekit-agent:latest
args: ["agent.py", "start", "--drain-timeout", "1800"]
# Or if using uv: args: ["run", "agent.py", "start", "--drain-timeout", "1800"]
env:
- name: ENVIRONMENT
value: "production"
# ensure liveness/readiness probes reflect acceptance of new jobs
readinessProbe:
httpGet:
path: /health/readiness
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
httpGet:
path: /health/liveness
port: 8080
initialDelaySeconds: 30
periodSeconds: 30
Important configuration and behavior
• terminationGracePeriodSeconds must be greater than or equal to your drain_timeout plus a buffer so Kubernetes waits long enough for the agent to finish draining.
• When the pod receives SIGTERM, the agent sets itself to draining and stops accepting new jobs (status WS_FULL), and waits up to drain_timeout for running jobs to complete.
• Use readiness probes that reflect worker readiness. When draining starts the agent will mark itself unavailable so Kubernetes (and load balancers) stop routing new work to it.
• If you wrap the agent in a shell script, ensure the script uses exec to start the agent (so SIGTERM is forwarded), e.g., exec uv run agent.py start --drain-timeout 1800.
Verification
• Watch logs for the "draining worker" message when you scale down or deploy.
• Test by triggering a rolling update and verifying new pods accept new sessions while old pods log drain messages and finish existing jobs.
If you want, I can:
• Provide a tailored Deployment manifest with your image name and specific drain_timeout value, or
• Suggest readinessProbe endpoints/commands based on your container’s health endpoints. Which would you prefer?, with interactive elementscool-lizard-26153
04/20/2026, 7:51 AMtall-airline-16756
04/20/2026, 7:52 AMAgentSession().start() and have no shell wrapper.
Good news: that setup is compatible with LiveKit’s graceful shutdown. Actions to ensure rolling deployments drain correctly:
1. Ensure the agent process receives SIGTERM
◦ You already have no wrapper, so the Python process will get SIGTERM. If you ever add an entrypoint script, start the agent with exec so signals propagate.
1. Run the agent in production/graceful mode / enable drain timeout
◦ Start the runtime that wires up shutdown handling (production start mode). Configure drain_timeout to the max time pods should wait for jobs to finish (default 1800s). If you’re invoking programmatically, ensure the AgentSession/AgentServer is initialized with the drain timeout option or start via the production CLI that accepts --drain-timeout.
1. Kubernetes pod settings
◦ Set terminationGracePeriodSeconds >= drain_timeout + buffer.
◦ Use RollingUpdate with conservative `maxUnavailable`/`maxSurge` values.
◦ Make readinessProbe reflect worker readiness so pods are removed from rotation when draining.
1. Verify behavior
◦ Start active jobs, send SIGTERM to the agent process (or trigger a rolling update/scale-down), and confirm logs show “draining worker,” the worker stops accepting new jobs (status becomes WS_FULL), and running jobs finish or time out by drain_timeout.
If you’d like, share:
• how you instantiate AgentSession (code snippet), and
• the drain_timeout you prefer and your current Pod spec (terminationGracePeriodSeconds),
and I’ll give a minimal code example showing where to set the drain timeout and a tailored Kubernetes Deployment snippet.
Sources: Deployment reliability on LiveKit Cloud | LiveKit | Deployment reliability on LiveKit Cloud | LiveKit | Server startup modes | LiveKit Documentation | Self-hosted deployments | LiveKit Documentation, with interactive elementscool-lizard-26153
04/20/2026, 7:55 AMtall-airline-16756
04/20/2026, 7:55 AMdrain_timeout for in-flight and running jobs to finish.
• If terminationGracePeriodSeconds (300s) is shorter than drain_timeout (1800s), Kubernetes will SIGKILL the pod before the agent’s drain period finishes, aborting running jobs and preventing a clean handoff.
How to configure correctly:
• Option A — Increase Kubernetes grace period:
◦ Set terminationGracePeriodSeconds >= drain_timeout + buffer (e.g., drain_timeout 1800s → terminationGracePeriodSeconds 1900–2000s).
• Option B — Decrease agent drain_timeout:
◦ Set --drain-timeout (or the AgentServer/AgentSession parameter) to a value <= terminationGracePeriodSeconds minus buffer (e.g., if you want 300s pod grace, set drain_timeout ≤ 270–290s).
• Add a small buffer (10–20s) so the process can perform final cleanup before SIGKILL.
Practical examples:
• If you keep drain_timeout default 1800s:
◦ Pod spec: terminationGracePeriodSeconds: 2000
• If you want pods to terminate within ~5 minutes:
◦ Start agent with: --drain-timeout 270 (or set the equivalent in AgentSession/AgentServer)
◦ Pod spec: terminationGracePeriodSeconds: 300
Verification steps:
1. Update values.
2. Trigger a rollout/scale-down with active jobs.
3. Confirm logs show “draining worker” and jobs finish before container exit.
4. Ensure no SIGKILL in logs (would show abrupt termination).
If you tell me which you prefer (increase pod grace or reduce drain_timeout) and your desired shutdown window, I’ll provide the exact command or Deployment snippet to apply.
, with interactive elementscool-lizard-26153
04/20/2026, 7:57 AMdrain_timeout?
Even if a call is in progress after the drain_timeout also, will the call be terminated abruptly?tall-airline-16756
04/20/2026, 7:58 AMdrain_timeout does and what happens to in-progress calls.
What drain_timeout does
• When the agent receives SIGTERM it enters drain mode: it marks the worker unavailable for new jobs (WS_FULL), finishes any in-flight job launches, and then waits for running jobs to complete.
• drain_timeout is the maximum time the agent will wait for those running jobs to finish before it proceeds with shutdown.
What happens when drain_timeout expires
• If running jobs (calls/sessions) have not completed by the end of drain_timeout, the agent will stop waiting and the process will continue shutdown. If the Kubernetes pod’s terminationGracePeriodSeconds has already elapsed, Kubernetes will send SIGKILL and the container will be forcefully terminated.
• In practice that means any still-active calls can be terminated abruptly when the agent gives up waiting and the container is killed.
Practical implications
• To avoid abrupt termination of in-progress calls, ensure:
◦ terminationGracePeriodSeconds >= drain_timeout + small buffer (10–30s) so Kubernetes does not SIGKILL the container before the agent finishes draining.
◦ drain_timeout is set to a value that matches how long you’re willing to wait for calls to finish (e.g., average/maximum call length).
• If you need a strict upper bound on pod shutdown time, reduce drain_timeout to that bound (and set pod grace a little larger). If you want to prioritize letting calls finish, increase pod grace to match a larger drain_timeout.
If you want, tell me your typical call length and desired maximum shutdown window and I’ll recommend concrete drain_timeout and terminationGracePeriodSeconds values.
, with interactive elementscool-lizard-26153
04/20/2026, 8:03 AMdrain_timeout and terminationGracePeriodSeconds?
terminationGracePeriodSeconds also hold the pod for those amout of seconds and not accept new jobs right?tall-airline-16756
04/20/2026, 8:04 AMdrain_timeout (agent): How long the LiveKit agent will wait, after receiving SIGTERM, for in-flight launches to finish and for running jobs/calls to complete before it stops waiting and proceeds with shutdown.
◦ terminationGracePeriodSeconds (Kubernetes): How long kubelet waits between sending SIGTERM and force-killing the container with SIGKILL.
• Why you need both
◦ Kubernetes only enforces the time window for the container process (SIGTERM → SIGKILL). It does not know about LiveKit’s internal drain logic or job state. The agent must be allowed enough time to perform its drain procedure; Kubernetes must be configured to wait at least that long. If Kubernetes’ grace period is shorter than the agent’s drain_timeout, Kubernetes will SIGKILL the pod before the agent finishes draining, causing abrupt termination.
◦ Conversely, if you set a long pod grace period but a very short drain_timeout, the agent will stop waiting early and proceed with shutdown even though Kubernetes would have waited longer — that can still abruptly cut calls.
• How they work together (correct relationship)
◦ terminationGracePeriodSeconds >= drain_timeout + small buffer (10–30s). This lets the agent finish its drain work and do cleanup before Kubernetes enforces SIGKILL.
• What actually happens to in-progress calls
◦ While the agent is within drain_timeout, it will keep running existing calls/sessions. After drain_timeout elapses the agent stops waiting; if the process then exits or Kubernetes reaches its grace window, remaining calls may be terminated abruptly (SIGKILL will forcibly stop the container).
• Practical guidance
◦ Pick the behavior you want:
▪︎ Let long calls finish: set drain_timeout to expected max call duration and set terminationGracePeriodSeconds slightly larger.
▪︎ Bound shutdown time: pick a shorter drain_timeout ≤ desired shutdown window and set terminationGracePeriodSeconds slightly larger.
◦ Always add a small buffer (10–30s) to terminationGracePeriodSeconds beyond the drain_timeout.
◦ Verify by testing: start calls, trigger SIGTERM/rolling update, watch for “draining worker” logs and that no SIGKILL occurs before jobs finish.
Would you like a recommended pair of values based on your typical call length and desired shutdown window?
, with interactive elementscool-lizard-26153
04/20/2026, 8:06 AMtall-airline-16756
04/20/2026, 8:06 AMdrain_timeout for running jobs to finish while Kubernetes’ countdown runs from terminationGracePeriodSeconds. They run in parallel — Kubernetes does not wait for drain_timeout to start.
Details:
• Sequence:
a. Kubelet sends SIGTERM to the container (this is immediate).
b. The agent receives SIGTERM and enters drain mode right away: it sets itself unavailable (status becomes WS_FULL) and will not accept new jobs.
c. Kubernetes starts the terminationGracePeriodSeconds timer. When that timer expires, kubelet sends SIGKILL.
d. Meanwhile the agent waits up to drain_timeout for in-flight launches and running jobs to complete. If drain_timeout elapses before jobs finish, the agent stops waiting and proceeds with shutdown; if Kubernetes’ grace period elapses first, the container is force-killed.
• Key point: terminationGracePeriodSeconds and drain_timeout run concurrently and both must be configured so the agent has enough time to finish draining. Ensure:
◦ terminationGracePeriodSeconds >= drain_timeout + small buffer (10–30s), or
◦ lower drain_timeout to fit within your desired pod shutdown window.
If you want, tell me your desired shutdown window or typical call length and I’ll recommend concrete drain_timeout and terminationGracePeriodSeconds values.
, with interactive elementscool-lizard-26153
04/20/2026, 8:07 AMtall-airline-16756
04/20/2026, 8:08 AMdrain_timeout cannot be set via an environment variable.
How to set it:
• Programmatically when creating the server:
server = AgentServer(drain_timeout=2400) # seconds
AgentSession(server=server).start()
• Or via CLI in production start mode:
uv run agent.py start --drain-timeout 2400
Notes:
• Default is 1800s (30 minutes).
• Keep Kubernetes' terminationGracePeriodSeconds >= drain_timeout + 10–30s buffer so the pod isn’t SIGKILL'd before draining completes.
If you want, share how you instantiate AgentSession in your code and your desired shutdown window and I’ll show the exact change to make.
Sources: Deployment reliability on LiveKit Cloud | LiveKit | Deployment reliability on LiveKit Cloud | LiveKit | Server options | LiveKit Documentation | Server startup modes | LiveKit Documentation, with interactive elements