Skip to content

Commit 2afac1f

Browse files
committed
Update job-manager.ts
1 parent 441cce1 commit 2afac1f

File tree

1 file changed

+19
-0
lines changed

1 file changed

+19
-0
lines changed

apps/media-server/src/lib/job-manager.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,24 @@ export interface Job {
5959
const jobs = new Map<string, Job>();
6060
const JOB_TTL_MS = 60 * 60 * 1000;
6161

62+
// Dynamic concurrency control for video processing.
63+
//
64+
// Instead of a manual counter (which drifted and caused permanent "server busy"
65+
// errors), active process count is derived from actual job state in the map.
66+
//
67+
// Concurrency limit is determined by:
68+
// 1. MEDIA_SERVER_MAX_CONCURRENT_VIDEO_PROCESSES env var (if set, used as ceiling)
69+
// 2. Otherwise: floor(cpuCount / 2), minimum 1
70+
// 3. Dynamically reduced when CPU load or process memory is high
71+
//
72+
// CPU throttling: when 1-minute load average per core exceeds 0.8,
73+
// effective max is scaled down proportionally.
74+
//
75+
// Memory throttling (opt-in): set MEDIA_SERVER_MEMORY_LIMIT_MB to the container's
76+
// memory limit. When process RSS exceeds 85% of that limit, effective max is reduced.
77+
// Uses process-level RSS (not system-wide free memory) so it works correctly on
78+
// shared hosts where os.freemem() reflects other tenants.
79+
6280
const configuredMaxProcesses =
6381
Number.parseInt(
6482
process.env.MEDIA_SERVER_MAX_CONCURRENT_VIDEO_PROCESSES ?? "0",
@@ -75,6 +93,7 @@ function isActivePhase(phase: JobPhase): boolean {
7593
return phase !== "complete" && phase !== "error" && phase !== "cancelled";
7694
}
7795

96+
// Derived from actual job state — no manual increment/decrement that can drift
7897
export function getActiveVideoProcessCount(): number {
7998
let count = 0;
8099
for (const job of jobs.values()) {

0 commit comments

Comments
 (0)