compute: centralize timeout config in compute-core and use in worker
This commit is contained in:
parent
0d494cf5e5
commit
fbb6f484ce
3 changed files with 48 additions and 6 deletions
|
|
@ -14,6 +14,7 @@
|
||||||
"exports": {
|
"exports": {
|
||||||
".": "./src/index.ts",
|
".": "./src/index.ts",
|
||||||
"./contracts": "./src/contracts.ts",
|
"./contracts": "./src/contracts.ts",
|
||||||
"./local-runtime": "./src/local-runtime.ts"
|
"./local-runtime": "./src/local-runtime.ts",
|
||||||
|
"./runtime/timeout-config": "./src/runtime/timeout-config.ts"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
39
compute/core/src/runtime/timeout-config.ts
Normal file
39
compute/core/src/runtime/timeout-config.ts
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
const DEFAULT_COMPUTE_WHISPER_TIMEOUT_MS = 30_000;
|
||||||
|
const DEFAULT_COMPUTE_PDF_TIMEOUT_MS = 300_000;
|
||||||
|
const DEFAULT_COMPUTE_PDF_HARD_CAP_MS = 24 * 60 * 60 * 1000;
|
||||||
|
const DEFAULT_WORKER_WAIT_BUFFER_MS = 15_000;
|
||||||
|
const DEFAULT_WORKER_WAIT_MIN_MS = 60_000;
|
||||||
|
|
||||||
|
export type ComputeTimeoutConfig = {
|
||||||
|
whisperTimeoutMs: number;
|
||||||
|
pdfTimeoutMs: number;
|
||||||
|
pdfHardCapMs: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ComputeOperationKind = 'whisper_align' | 'pdf_layout';
|
||||||
|
|
||||||
|
function readPositiveIntEnv(name: string, fallback: number): number {
|
||||||
|
const raw = process.env[name]?.trim();
|
||||||
|
if (!raw) return fallback;
|
||||||
|
const parsed = Number(raw);
|
||||||
|
if (!Number.isFinite(parsed) || parsed <= 0) return fallback;
|
||||||
|
return Math.floor(parsed);
|
||||||
|
}
|
||||||
|
|
||||||
|
let timeoutConfigCache: ComputeTimeoutConfig | null = null;
|
||||||
|
|
||||||
|
export function getComputeTimeoutConfig(): ComputeTimeoutConfig {
|
||||||
|
if (timeoutConfigCache) return timeoutConfigCache;
|
||||||
|
timeoutConfigCache = {
|
||||||
|
whisperTimeoutMs: readPositiveIntEnv('COMPUTE_WHISPER_TIMEOUT_MS', DEFAULT_COMPUTE_WHISPER_TIMEOUT_MS),
|
||||||
|
pdfTimeoutMs: readPositiveIntEnv('COMPUTE_PDF_TIMEOUT_MS', DEFAULT_COMPUTE_PDF_TIMEOUT_MS),
|
||||||
|
pdfHardCapMs: DEFAULT_COMPUTE_PDF_HARD_CAP_MS,
|
||||||
|
};
|
||||||
|
return timeoutConfigCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getWorkerClientWaitTimeoutMs(kind: ComputeOperationKind): number {
|
||||||
|
const config = getComputeTimeoutConfig();
|
||||||
|
const timeoutMs = kind === 'pdf_layout' ? config.pdfTimeoutMs : config.whisperTimeoutMs;
|
||||||
|
return Math.max(DEFAULT_WORKER_WAIT_MIN_MS, timeoutMs + DEFAULT_WORKER_WAIT_BUFFER_MS);
|
||||||
|
}
|
||||||
|
|
@ -27,6 +27,7 @@ import {
|
||||||
runPdfLayoutFromPdfBuffer,
|
runPdfLayoutFromPdfBuffer,
|
||||||
runWhisperAlignmentFromAudioBuffer,
|
runWhisperAlignmentFromAudioBuffer,
|
||||||
} from '@openreader/compute-core/local-runtime';
|
} from '@openreader/compute-core/local-runtime';
|
||||||
|
import { getComputeTimeoutConfig } from '@openreader/compute-core/runtime/timeout-config';
|
||||||
import {
|
import {
|
||||||
type PdfLayoutJobRequest,
|
type PdfLayoutJobRequest,
|
||||||
type PdfLayoutJobResult,
|
type PdfLayoutJobResult,
|
||||||
|
|
@ -56,7 +57,6 @@ const RUNNING_HEARTBEAT_MS = 5000;
|
||||||
const DOCUMENT_ID_REGEX = /^[a-f0-9]{64}$/i;
|
const DOCUMENT_ID_REGEX = /^[a-f0-9]{64}$/i;
|
||||||
const SAFE_NAMESPACE_REGEX = /^[a-zA-Z0-9._-]{1,128}$/;
|
const SAFE_NAMESPACE_REGEX = /^[a-zA-Z0-9._-]{1,128}$/;
|
||||||
const WHISPER_MAX_DELIVER = 1;
|
const WHISPER_MAX_DELIVER = 1;
|
||||||
const PDF_LAYOUT_HARD_CAP_MS = 24 * 60 * 60 * 1000;
|
|
||||||
const NATS_API_TIMEOUT_MS = 60_000;
|
const NATS_API_TIMEOUT_MS = 60_000;
|
||||||
|
|
||||||
interface QueuedJob<TPayload> {
|
interface QueuedJob<TPayload> {
|
||||||
|
|
@ -472,10 +472,12 @@ async function main(): Promise<void> {
|
||||||
const host = process.env.COMPUTE_WORKER_HOST?.trim() || '0.0.0.0';
|
const host = process.env.COMPUTE_WORKER_HOST?.trim() || '0.0.0.0';
|
||||||
const workerToken = requireEnv('COMPUTE_WORKER_TOKEN');
|
const workerToken = requireEnv('COMPUTE_WORKER_TOKEN');
|
||||||
const natsUrl = requireEnv('NATS_URL');
|
const natsUrl = requireEnv('NATS_URL');
|
||||||
|
const timeoutConfig = getComputeTimeoutConfig();
|
||||||
|
|
||||||
const jobConcurrency = readIntEnv('COMPUTE_JOB_CONCURRENCY', 1);
|
const jobConcurrency = readIntEnv('COMPUTE_JOB_CONCURRENCY', 1);
|
||||||
const whisperTimeoutMs = readIntEnv('COMPUTE_WHISPER_TIMEOUT_MS', 30_000);
|
const whisperTimeoutMs = timeoutConfig.whisperTimeoutMs;
|
||||||
const pdfTimeoutMs = readIntEnv('COMPUTE_PDF_TIMEOUT_MS', 5 * 60_000);
|
const pdfTimeoutMs = timeoutConfig.pdfTimeoutMs;
|
||||||
|
const pdfHardCapMs = timeoutConfig.pdfHardCapMs;
|
||||||
const pdfAttempts = readIntEnv('COMPUTE_PDF_JOB_ATTEMPTS', 1);
|
const pdfAttempts = readIntEnv('COMPUTE_PDF_JOB_ATTEMPTS', 1);
|
||||||
const prewarmModels = parseBoolEnv('COMPUTE_PREWARM_MODELS', true);
|
const prewarmModels = parseBoolEnv('COMPUTE_PREWARM_MODELS', true);
|
||||||
const jobsStreamMaxBytes = readIntEnv('COMPUTE_JOBS_STREAM_MAX_BYTES', 256 * 1024 * 1024);
|
const jobsStreamMaxBytes = readIntEnv('COMPUTE_JOBS_STREAM_MAX_BYTES', 256 * 1024 * 1024);
|
||||||
|
|
@ -560,7 +562,7 @@ async function main(): Promise<void> {
|
||||||
availableCpuCores: getAvailableCpuCores(),
|
availableCpuCores: getAvailableCpuCores(),
|
||||||
onnxThreadsPerJob: getOnnxThreadsPerJob(jobConcurrency),
|
onnxThreadsPerJob: getOnnxThreadsPerJob(jobConcurrency),
|
||||||
natsApiTimeoutMs: NATS_API_TIMEOUT_MS,
|
natsApiTimeoutMs: NATS_API_TIMEOUT_MS,
|
||||||
pdfLayoutHardCapMs: PDF_LAYOUT_HARD_CAP_MS,
|
pdfLayoutHardCapMs: pdfHardCapMs,
|
||||||
}, 'compute runtime config');
|
}, 'compute runtime config');
|
||||||
|
|
||||||
const opIndexCodec = createJsonCodec<OpIndexEntry>();
|
const opIndexCodec = createJsonCodec<OpIndexEntry>();
|
||||||
|
|
@ -914,7 +916,7 @@ async function main(): Promise<void> {
|
||||||
const computeStartedAt = Date.now();
|
const computeStartedAt = Date.now();
|
||||||
const result = await withIdleTimeoutAndHardCap({
|
const result = await withIdleTimeoutAndHardCap({
|
||||||
idleTimeoutMs: Math.max(pdfTimeoutMs, 1_000),
|
idleTimeoutMs: Math.max(pdfTimeoutMs, 1_000),
|
||||||
hardCapMs: PDF_LAYOUT_HARD_CAP_MS,
|
hardCapMs: pdfHardCapMs,
|
||||||
label: 'pdf layout job',
|
label: 'pdf layout job',
|
||||||
run: async (touchProgress) => runPdfLayoutFromPdfBuffer({
|
run: async (touchProgress) => runPdfLayoutFromPdfBuffer({
|
||||||
documentId: parsed.documentId,
|
documentId: parsed.documentId,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue