diff --git a/compute/worker/.env.example b/compute/worker/.env.example index 901417a..36a9939 100644 --- a/compute/worker/.env.example +++ b/compute/worker/.env.example @@ -27,3 +27,5 @@ S3_FORCE_PATH_STYLE=true # Queue + execution tuning COMPUTE_PREWARM_MODELS=true +COMPUTE_JOBS_STREAM_MAX_BYTES=268435456 +COMPUTE_JOB_STATES_MAX_BYTES=67108864 diff --git a/compute/worker/src/server.ts b/compute/worker/src/server.ts index 4e62162..c59150e 100644 --- a/compute/worker/src/server.ts +++ b/compute/worker/src/server.ts @@ -243,12 +243,14 @@ async function ensureJetStreamResources( whisperTimeoutMs: number, pdfTimeoutMs: number, attempts: number, + maxBytes: number, ): Promise { const streamConfig = { name: JOBS_STREAM_NAME, subjects: [WHISPER_JOBS_SUBJECT, LAYOUT_JOBS_SUBJECT], retention: RetentionPolicy.Workqueue, storage: StorageType.File, + max_bytes: maxBytes, }; try { @@ -257,6 +259,7 @@ async function ensureJetStreamResources( if (!isAlreadyExistsError(error)) throw error; await jsm.streams.update(JOBS_STREAM_NAME, { subjects: [WHISPER_JOBS_SUBJECT, LAYOUT_JOBS_SUBJECT], + max_bytes: maxBytes, }); } @@ -414,6 +417,8 @@ async function main(): Promise { const pdfTimeoutMs = readIntEnv('COMPUTE_PDF_TIMEOUT_MS', 90_000); const attempts = readIntEnv('COMPUTE_JOB_ATTEMPTS', 2); const prewarmModels = parseBoolEnv('COMPUTE_PREWARM_MODELS', true); + const jobsStreamMaxBytes = readIntEnv('COMPUTE_JOBS_STREAM_MAX_BYTES', 256 * 1024 * 1024); + const jobStatesMaxBytes = readIntEnv('COMPUTE_JOB_STATES_MAX_BYTES', 64 * 1024 * 1024); const connectOpts: any = { servers: natsUrl }; const natsCreds = process.env.NATS_CREDS?.trim(); @@ -433,11 +438,12 @@ async function main(): Promise { const js: JetStreamClient = jetstream(nc); const jsm: JetStreamManager = await jetstreamManager(nc); - await ensureJetStreamResources(jsm, whisperTimeoutMs, pdfTimeoutMs, attempts); + await ensureJetStreamResources(jsm, whisperTimeoutMs, pdfTimeoutMs, attempts, jobsStreamMaxBytes); const kv = await new Kvm(js).create(JOB_STATES_BUCKET, { history: 1, ttl: JOB_STATES_TTL_MS, + max_bytes: jobStatesMaxBytes, }); const s3 = buildS3Client(); diff --git a/docs-site/docs/deploy/compute-worker.md b/docs-site/docs/deploy/compute-worker.md index 8e2da44..f5b0885 100644 --- a/docs-site/docs/deploy/compute-worker.md +++ b/docs-site/docs/deploy/compute-worker.md @@ -45,6 +45,8 @@ Common optional: - `COMPUTE_WORKER_PORT=8081` - `COMPUTE_LOG_FORMAT=pretty` (default) or `json` - `COMPUTE_PREWARM_MODELS=true` +- `COMPUTE_JOBS_STREAM_MAX_BYTES=268435456` (256MB JetStream jobs stream cap) +- `COMPUTE_JOB_STATES_MAX_BYTES=67108864` (64MB JetStream KV bucket cap) ## App server environment variables (worker mode) @@ -102,6 +104,8 @@ Set these in the Railway worker service: COMPUTE_WORKER_HOST=0.0.0.0 COMPUTE_WORKER_PORT=8081 COMPUTE_WORKER_TOKEN= +COMPUTE_JOBS_STREAM_MAX_BYTES=268435456 +COMPUTE_JOB_STATES_MAX_BYTES=67108864 NATS_URL=tls://connect.ngs.global:4222 NATS_CREDS="-----BEGIN NATS USER JWT----- @@ -122,6 +126,7 @@ Notes: - `NATS_CREDS` should be the full Synadia `.creds` file content, including begin/end markers. - Keep `COMPUTE_WORKER_TOKEN` identical between app server and worker. - If your platform supports mounted files, you can use `NATS_CREDS_FILE` instead of `NATS_CREDS`. +- `COMPUTE_JOBS_STREAM_MAX_BYTES` and `COMPUTE_JOB_STATES_MAX_BYTES` are optional; defaults are `268435456` (256MiB) and `67108864` (64MiB). ### 4. Configure the OpenReader app server (worker mode)