steep-shampoo-86436
03/03/2026, 11:33 AMload_threshold and load_fnctall-airline-16756
03/03/2026, 11:33 AMtall-airline-16756
03/03/2026, 11:33 AMload_threshold and load_fnc for a local OKE deployment.
Quick summary of recommended starting point
• Pod/node size: start with nodes sized at 4 vCPU and 8 GB RAM and set each agent server pod requests/limits to match (4 CPU, 8Gi).
• Agents per pod: run one AgentServer instance per pod and scale horizontally (many pods) rather than packing multiple agent servers into a single pod.
• `load_fnc`: default is average CPU utilization (over a short window, e.g., 5s). You can replace it with a function that reports load as a 0–1 value (for example, active jobs / max_jobs).
• `load_threshold`: default is 0.7 (server accepts new jobs while load < 0.7). Use this as a safe starting point.
Why this baseline
• 4 vCPU / 8GB is a practical balance for typical voice/AI workloads and can handle roughly 10–25 concurrent jobs depending on model complexity and processing used. If you use heavier models or additional processing (noise reduction, large ML models), you’ll need more resources per pod.
• Running a single AgentServer per pod keeps isolation simple and makes Kubernetes autoscaling behave predictably (scale pods, not internal processes).
Concrete tuning guidance and examples
1. Start small and measure
◦ Deploy pods with requests/limits = 4 CPU / 8Gi.
◦ Run a realistic synthetic load to observe CPU, memory, and active job counts.
◦ Monitor how many concurrent jobs each pod actually supports before becoming CPU-bound.
1. Autoscaling signals
◦ Scale out pods when average CPU across pods approaches ~0.5 to avoid hitting the load_threshold of 0.7.
◦ Use a HorizontalPodAutoscaler based on CPU or custom metrics (active job count) depending on which correlates best with service quality.
1. Customizing load_fnc and load_threshold
◦ Default approach (CPU-based):
▪︎ load_fnc returns average CPU utilization normalized to 0–1.
▪︎ load_threshold = 0.7.
◦ Alternative approach (active job count):
▪︎ If you prefer to limit by active jobs, implement load_fnc that returns min(active_jobs / max_jobs, 1.0).
▪︎ Example Python pattern:
server = AgentServer(load_threshold=0.9)
def compute_load(agent_server: AgentServer) -> float:
return min(len(agent_server.active_jobs) / 10, 1.0)
server.load_fnc = compute_load
• In this example `max_jobs = 10`; tune max_jobs after observing real performance.
1. Termination/drain considerations
◦ Set terminationGracePeriodSeconds to allow in-flight/long-running sessions to finish (10+ minutes may be needed for voice agents). This avoids abruptly killing active jobs during rolling updates.
Questions to narrow recommendations
• What does a “job” look like in your environment? (short voice tasks vs long-running transcription/AI model inference)
• What models/features are you using (simple voice processing vs heavy ML models or GPU inference)?
• Do you have GPU nodes or are you CPU-only?
• What peak concurrency do you expect across the cluster?
If you share this info I’ll help you pick:
• a tuned pod size,
• a suggested max_jobs (if you use job-count-based load_fnc),
• autoscaler target values (CPU% or custom metric thresholds),
• and an example Kubernetes manifest snippet for requests/limits and HPA. Sources: Self-hosted deployments | LiveKit Documentation | Server options | LiveKit Documentationsteep-shampoo-86436
03/03/2026, 11:49 AMtall-airline-16756
03/03/2026, 11:49 AMload_fnc which must return a value in [0,1]. If that value is >= load_threshold, the server will stop accepting new jobs.
• To limit to 7 agents, make load_fnc return active_jobs / 7 (clamped to 1.0) and set load_threshold slightly below 1.0 so the server stops accepting new jobs when it reaches 7.
Example (Python)
1. Create the server with a threshold of 0.9.
2. Use a compute_load function that returns min(active_jobs / 7, 1.0).
from livekit.agents import AgentServer
# set threshold slightly below 1.0 so 7 jobs cause the server to stop accepting more
server = AgentServer(load_threshold=0.9)
def compute_load(agent_server: AgentServer) -> float:
# agent_server.active_jobs is the list of currently running jobs
return min(len(agent_server.active_jobs) / 7.0, 1.0)
server.load_fnc = compute_load
Practical tips for OKE/Kubernetes
• One AgentServer per pod: run a single AgentServer instance in each pod and use horizontal scaling (multiple pods) rather than packing multiple AgentServers in one pod.
• Resource requests/limits: match pod CPU/RAM to expected load (a good starting baseline is 4 vCPU / 8Gi per pod for typical voice AI workloads). Adjust up if your jobs use heavier models or additional processing.
• Autoscaling: configure your HPA to scale out before pods hit the 7-job limit. For example, scale-up when average jobs per pod reaches 5–6, or when CPU utilization is ~50%.
• Observability: monitor active job counts, CPU, and memory. Tune the divisor (7) and load_threshold as you observe real traffic.
• Graceful termination: set terminationGracePeriodSeconds long enough (e.g., 10+ minutes) so in-flight jobs aren’t killed during rollouts.
If you want, I can:
• Produce a Kubernetes pod manifest example with resource requests/limits and an HPA configured to scale based on a custom metric (active jobs) or CPU.
• Recommend precise HPA thresholds if you share expected job duration, typical CPU usage per job, and whether you’re using GPU nodes. Sources: Server options | LiveKit Documentation | Self-hosted deployments | LiveKit Documentationsteep-shampoo-86436
03/03/2026, 11:53 AMtall-airline-16756
03/03/2026, 11:53 AMAgentServer process. That AgentServer manages its own jobs and reporting of load.
• The alternative (not recommended) is to run multiple AgentServer processes inside a single pod. That groups multiple independent servers into one Kubernetes scheduling/termination unit.
Why we recommend one AgentServer per pod
• Predictable scaling: Kubernetes scales pods. If each pod is exactly one AgentServer, adding pods increases capacity in a 1:1 way.
• Resource isolation: Resource requests/limits, pod scheduling, and node placement apply to the whole pod. When one AgentServer = one pod, you know how much CPU/RAM each server will get.
• Simpler autoscaling and metrics: HPA or custom metrics can measure per-pod CPU or active-job count and scale pods accordingly. If a pod contains multiple AgentServers, mapping metrics to capacity becomes harder.
• Easier lifecycle management: Pod termination, rolling updates, and graceful draining are simpler when there’s a single server to drain per pod. This reduces risk of killing multiple servers at once.
• Troubleshooting: Logs, crashes, resource spikes, and restarts are easier to correlate to a single AgentServer instance.
How this applies to your setup (agent "x" with 24 pods)
• If each of those 24 pods runs one AgentServer instance, that matches the recommended pattern: you effectively have 24 AgentServers and scale capacity by adding/removing pods.
• If those 24 pods each run multiple AgentServer processes, you should consider moving to one AgentServer per pod because:
◦ You’ll get clearer capacity planning (e.g., “24 pods × max 7 agents per pod = 168 concurrent agents”).
◦ Autoscaling can be based on per-pod metrics rather than complex intra-pod counts.
Quick checks you can run
1. Inspect the pod spec for agent "x":
◦ Look at the container command or entrypoint. Does it start one AgentServer or multiple processes?
◦ Count processes in a running pod (e.g., kubectl exec -it <pod> -- ps aux).
1. Confirm resource requests/limits:
◦ If a pod runs multiple AgentServers but requests resources sized for a single server, you may be overloading the pod.
1. Check your metrics:
◦ Are you scaling HPA based on pod CPU or a custom metric? Does that metric reflect the number of AgentServers inside the pod?
If your current 24 pods already each run one AgentServer, you’re aligned with the recommendation. If not, tell me:
• Whether each pod currently runs one process or multiple processes,
• What your desired max agents per pod is (you previously said 7),
• If you want an example pod manifest or an HPA example to scale to the target capacity.
I can then give a concrete plan:
• how many pods you need for a given target concurrency,
• a sample Kubernetes manifest that runs one AgentServer per pod with proper requests/limits,
• an HPA recipe (CPU-based or custom metric based on active job count) to scale smoothly.steep-shampoo-86436
03/03/2026, 12:02 PMtall-airline-16756
03/03/2026, 12:02 PMcompute_load returns a normalized load in [0,1] by dividing current active jobs by MAX_CONCURRENT_AGENTS (7).
• With load_threshold=0.9, once a pod reaches 7 active jobs the returned load will be 1.0, which is above 0.9, so the server will stop accepting new jobs. This enforces the 7-agents-per-pod limit as intended.
Minor improvements and a corrected example
• Use consistent names and types used by your runtime (you used WorkerOptions and options.active_jobs — that matches your environment). Ensure the function signature matches the expected callback type (some SDKs expect the server instance or options type; your snippet looks consistent with options: WorkerOptions).
• Add simple guards to avoid division by zero and keep the code clear.
Example (cleaned and ready to drop in):
MAX_CONCURRENT_AGENTS = 7
def compute_load(options: WorkerOptions) -> float:
# Ensure MAX_CONCURRENT_AGENTS is positive
if MAX_CONCURRENT_AGENTS <= 0:
return 1.0
return min(len(options.active_jobs) / float(MAX_CONCURRENT_AGENTS), 1.0)
cli.run_app(
WorkerOptions(
entrypoint_fnc=partial(entrypoint, avatar_dispatcher_url=args.avatar_url),
prewarm_fnc=prewarm,
worker_type=WorkerType.ROOM,
agent_name=AGENT_NAME,
load_fnc=compute_load,
load_threshold=0.9,
)
)
Operational tips
• Test under load: run a load test to confirm that 7 active jobs produces the expected CPU/memory profile and that pods stop accepting new jobs once full.
• Autoscaling: configure your HPA to scale pods before they reach the 7-job limit (e.g., scale up when average jobs per pod is 5–6 or when CPU ~50%) so you don’t run out of capacity.
• Observability: emit/collect the active job count as a metric so you can create alerts/ dashboards and tune MAX_CONCURRENT_AGENTS if needed.
• Graceful shutdown: keep a long enough terminationGracePeriodSeconds so pods can finish in-flight jobs when being drained.
If you want, I can:
• Provide an example Kubernetes Deployment manifest that runs one AgentServer per pod with resource requests/limits,
• Show a HorizontalPodAutoscaler example using a custom metric (active jobs) or CPU,
• Help you pick HPA thresholds if you share typical job duration and per-job CPU usage.
Would you like the manifest + HPA examples? If so, tell me whether you prefer CPU-based or active-job-count autoscaling.steep-shampoo-86436
03/03/2026, 12:03 PMtall-airline-16756
03/03/2026, 12:04 PMterminationGracePeriodSeconds: 600 (10 minutes) or higher if jobs are longer.
◦ Implement a PreStop hook or SIGTERM handler in your app that:
▪︎ stops accepting new jobs
▪︎ waits for in-flight jobs to finish (or checkpoint)
▪︎ then exits
1. Configure Deployment rollout behavior:
◦ set strategy:
▪︎ type: RollingUpdate
▪︎ rollingUpdate:
▪︎ maxUnavailable: 10% (or 1)
▪︎ maxSurge: 1 (or 25%)
◦ This ensures Kubernetes only replaces a small number of pods at a time.
1. Trigger the rollout:
◦ kubectl apply -f deployment.yaml
◦ Monitor: kubectl rollout status deployment/<name>
◦ Watch metrics (active job counts, CPU, error rates) while pods update.
1. If you see problems, rollback:
◦ kubectl rollout undo deployment/<name>
Canary flow (more cautious)
1. Create a canary Deployment with a small replica count (e.g., 1–2 pods) or label (version: v2).
2. Route a small portion of traffic to canary (service selector or ingress split).
3. Monitor for errors, latency, resource usage for a period.
4. Gradually increase canary pods or traffic percentage until full rollout.
Blue/Green flow (full isolation)
1. Stand up green environment (Deployment + Service) using new images/config.
2. Warm pods until readiness is true and metrics are normal.
3. Switch a Service to point to green (update selector or update ingress).
4. Keep blue running for a rollback plan, then decommission.
Recommended default config values to start with
• readinessProbe: HTTP GET /healthz or a custom endpoint; initialDelaySeconds: 10–30; periodSeconds: 5
• livenessProbe: HTTP GET /healthz; failureThreshold: 3; periodSeconds: 15
• terminationGracePeriodSeconds: 600 (10 minutes)
• Deployment strategy:
◦ maxUnavailable: 10% (or 1)
◦ maxSurge: 25% (or 1)
• HPA: scale up when CPU ~50% or when average active jobs per pod >= 5 (if you expose active jobs as a metric)
Example rollout commands to monitor
• Start rollout: kubectl apply -f deployment.yaml
• Watch rollout: kubectl rollout status deployment/<agent-deployment>
• Inspect pods: kubectl get pods -l app=<agent> -o wide
• See pod termination events: kubectl describe pod <pod-name>
• Rollback if needed: kubectl rollout undo deployment/<agent-deployment>
Operational checklist before you deploy
• Confirm readiness probe only becomes true when the agent is ready (warm models loaded).
• Confirm SIGTERM handling lets existing jobs finish or checkpoint within terminationGracePeriodSeconds.
• Ensure metrics/alerts are in place (active jobs, CPU, error rates).
• If using HPA, temporarily raise min replicas during rollout if you expect transient increased load.
• Perform a small canary before full rollout for high-risk changes.
If you want, I can:
• Provide a sample Kubernetes Deployment manifest with readiness/liveness probes, PreStop hook, terminationGracePeriodSeconds set, and RollingUpdate strategy.
• Provide an example HPA manifest (CPU-based or custom active-job metric) and how to expose active job count using a simple metrics exporter.
• Walk through an example canary manifest and service-splitting for traffic percentage.
Which would you like next — a Deployment + HPA manifest, or a canary example? Also tell me whether your AgentServer exposes a health endpoint currently and how long typical jobs run so I can tune terminationGracePeriodSeconds.