future-engineer-7239
05/14/2026, 5:40 AMtall-airline-16756
05/14/2026, 5:40 AMtall-airline-16756
05/14/2026, 5:41 AM--shm-size for containers (512MB–1GB or more per Chrome instance) to avoid Chrome shared-memory issues.
• Chromium flags:
◦ Run Chrome headless with flags like --disable-dev-shm-usage --disable-gpu --no-sandbox --disable-software-rasterizer and set a fixed viewport to reduce overhead.
• CPU pinning / cgroups:
◦ Pin or limit CPU for Egress containers/pods so each Chrome process has stable cores; use CPU requests/limits in k8s to avoid noisy neighbor contention.
• Redis:
◦ Use a low-latency Redis (same region), monitor Pub/Sub queue depth, and ensure HA (replication/failover) so Egress job dispatch is reliable.
• Kubernetes autoscaling:
◦ Autoscale based on CPU (e.g., trigger scale up >70% CPU for sustained period) and queue-depth metrics. Set a generous terminationGracePeriodSeconds so active recordings can finish.
◦ Use node taints/tolerations or separate node pools to dedicate nodes for Egress workloads.
• GPU acceleration:
◦ GPU can reduce CPU by offloading encoding (e.g., NVENC), but it’s advanced: requires GPU-enabled nodes, matching GStreamer/encoder pipeline, and additional ops complexity. Not officially turnkey.
• File upload throughput:
◦ Use the cloud provider’s SDKs and multipart uploads (Azure Blob multipart) for resilience and throughput.
◦ Ensure sufficient network bandwidth on Egress nodes and monitor upload latencies; avoid uploading directly from overloaded nodes if possible (or stream to a durable buffer).
• shm_size, memory, container limits:
◦ Ensure each Egress replica has adequate memory and shm; set container memory limits high enough to avoid OOM kills.
Quick operational checklist to reduce failures you observed
• Isolate Egress to dedicated replicas/nodes (don’t co-locate heavy services).
• Increase shm_size to >= 512MB–1GB for each Egress container.
• Add more Egress replicas and ensure Redis is healthy and low-latency.
• Add CPU-based autoscaling and monitor queue depth; scale before CPU saturates.
• Use multipart uploads and ensure upload bandwidth is sufficient.
• Capture and monitor these metrics per worker: CPU, memory, shm usage, container restarts, Redis queue depth, and upload error rates — use them to tune replica count and VM sizing.
If you want, I can:
• Suggest concrete container CPU/memory requests & limits and shm_size values to test for your environment.
• Propose a simple autoscaling policy (CPU + Redis queue depth) for k8s.
Which would you prefer me to provide next?
Sources: Universal Egress | LiveKit | Universal Egress | LiveKit | LiveKit Inference | Fast, reliable access to voice AI models | LiveKit, with interactive elementsfuture-engineer-7239
05/14/2026, 8:20 AMtall-airline-16756
05/14/2026, 8:21 AMfuture-cpu-86293
05/19/2026, 6:52 PMtall-airline-16756
05/19/2026, 6:52 PMfuture-cpu-86293
05/19/2026, 6:55 PMtall-airline-16756
05/19/2026, 6:56 PMcanvas.captureStream()).
b. Publish that single composited track.
c. Use Track Composite to record that merged track (gives you one MP4 without server-side Chromium).
◦ Pros: much lower server CPU (no headless Chrome). Cons: depends on publisher device CPU and network.
• Multiple Track Composite recordings (workaround):
◦ Start separate Track Composite egresses: one for the camera track + audio and another for the screen track + audio.
◦ Post-process (server-side) to combine them into a single file (e.g., ffmpeg overlay) if you need one file.
◦ Pros: keeps recording server-side; Cons: extra storage/processing and complexity.
• Stick with Room Composite:
◦ If you need server-controlled layout, dynamic UI overlays, or multi-participant layouts, Room Composite is the direct solution (uses headless Chromium).
Recommendation:
• If you want to reduce Egress CPU and can control the publisher: use client-side compositing + Track Composite.
• If you cannot rely on publisher devices or need server-side layout/UI, continue using Room Composite and scale Egress accordingly.
If you want, I can:
• Provide a small example (React + canvas) to publish a composited track.
• Or show the Track Composite request format to record a specific track and a simple ffmpeg command to merge two recordings. Which would you like? Sources: Universal Egress | LiveKit | Streaming video from a canvas with WebRTC and React | LiveKit, with interactive elementsfuture-cpu-86293
05/19/2026, 6:59 PMtall-airline-16756
05/19/2026, 7:00 PMdocker stats or k8s metrics.
4) Steps
1. Baseline:
◦ Start 1 client publisher + 1 Track Composite recording. Verify successful MP4 creation and upload.
◦ Record baseline CPU/memory/shm/upload times.
1. Ramp:
◦ Increase concurrent publishers in steps: 1, 2, 4, 6, 8, 10… until failure rate rises or CPU ~80–90%.
◦ At each step, run for 5–10 minutes to measure steady state.
1. Observe:
◦ Metrics: CPU, memory, shm, container restarts, Redis queue depth, egress_aborted/errors, upload failure rate, time-to-upload.
1. Failure validation:
◦ When failures appear, capture logs from Egress containers (start signal, can not accept request, egress_aborted).
1. Repeat with variations:
◦ Lower resolution/bitrate; switch from Room Composite to Track Composite; try multipart uploads; try different shm_size.
5) Success criteria
• Recording success rate >= 99% over 10 minutes at target concurrency.
• CPU per node < 80% sustained (headroom for peaks).
• Upload latency acceptable (e.g., <30s for MP4 uploads) and no container OOMs/restarts.
6) Actions based on results
• If CPU saturates: switch to more nodes (horizontal scale), reduce resolution/bitrate, or use client-side compositing (which you are testing).
• If uploads fail: increase network bandwidth, use multipart uploads, or offload uploads to a separate uploader service.
Small React + canvas example (minimal, focused on compositing camera over screen and publishing one merged track)
Notes:
• This example assumes you already have LiveKit JS installed and a token/URL from your server.
• It uses canvas.captureStream() to create a single outgoing video track combining screen and camera.
1) Key idea (pseudocode)
• Get camera MediaStream (getUserMedia)
• Get screen MediaStream (getDisplayMedia)
• Draw screen frames to a canvas, draw camera as a small overlay, update at 30 FPS
• Use canvas.captureStream(30) to get a composited stream
• Add composited video track + original microphone audio track to LiveKit room and publish
2) Minimal React component (JSX-like, abbreviated)
import React, { useRef, useEffect } from "react";
import { connect } from "livekit-client"; // placeholder import name
export default function CompositedPublisher({ url, token }) {
const videoRef = useRef(null);
const canvasRef = useRef(null);
const rafRef = useRef(null);
useEffect(() => {
let pc;
let cameraStream, screenStream, micTrack, compositedStream;
async function start() {
// 1. connect to LiveKit
const room = await connect(url, token);
// 2. get camera and mic
cameraStream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true });
const cameraTrack = cameraStream.getVideoTracks()[0];
micTrack = cameraStream.getAudioTracks()[0];
// 3. get screen
screenStream = await navigator.mediaDevices.getDisplayMedia({ video: true });
const screenTrack = screenStream.getVideoTracks()[0];
// 4. setup canvas
const canvas = document.createElement("canvas");
canvas.width = 1280; // target resolution
canvas.height = 720;
canvasRef.current = canvas;
const ctx = canvas.getContext("2d");
// 5. preview (optional)
if (videoRef.current) videoRef.current.srcObject = canvas.captureStream(30);
// 6. draw loop
function draw() {
// draw screen frame
if (screenStream) {
const [sVideo] = screenStream.getVideoTracks();
// draw video frame by drawing an offscreen video element
}
// For simplicity, create hidden video elements
// (Simplified; in production reuse elements and check readyState)
// draw screen full
// draw camera small overlay at bottom-right
rafRef.current = requestAnimationFrame(draw);
}
draw();
// 7. capture composited stream
compositedStream = canvas.captureStream(30);
const compositedTrack = compositedStream.getVideoTracks()[0];
// 8. publish composited video + mic
await room.localParticipant.publishTrack(compositedTrack);
await room.localParticipant.publishTrack(micTrack);
}
start();
return () => {
cancelAnimationFrame(rafRef.current);
// stop tracks and disconnect
};
}, [url, token]);
return (
<div>
<video ref={videoRef} autoPlay muted playsInline style={{ width: 640 }} />
</div>
);
}
3) Practical notes for production
• Reuse hidden video elements to render camera and screen frames into canvas (avoid creating new elements each frame).
• Set canvas size to target recording resolution to avoid runtime scaling.
• Use canvas.captureStream() with an appropriate FPS (e.g., 24 or 30) and set bitrate constraints via RTCRtpSender parameters if needed.
• Test CPU usage on publisher devices — compositing is CPU-heavy on client side.
• Publish only the composited track (and mic) to simplify server-side recording.
If you want, I can:
• Provide a complete, copy-paste React component with real draw loop using hidden video elements and cleanup logic.
• Provide example LiveKit Track Composite API request body to record the published track.
Which would you like next?
, with interactive elements