@systemfsoftware/trigger.dev
Version:
A Command-Line Interface for Trigger.dev (v3) projects
224 lines (223 loc) • 7.28 kB
JavaScript
// src/workers/prod/worker-facade.ts
import {
ProdChildToWorkerMessages,
ProdWorkerToChildMessages,
clock,
taskCatalog
} from "@systemfsoftware/trigger.dev_core/v3";
import {
ConsoleInterceptor,
DevUsageManager,
DurableClock,
OtelTaskLogger,
ProdUsageManager,
TaskExecutor,
getEnvVar,
logLevels,
usage
} from "@systemfsoftware/trigger.dev_core/v3/workers";
import { ZodIpcConnection } from "@systemfsoftware/trigger.dev_core/v3/zodIpc";
import { ZodSchemaParsedError } from "@systemfsoftware/trigger.dev_core/v3/zodMessageHandler";
import "source-map-support/register.js";
import {
TaskRunErrorCodes,
TriggerTracer,
logger,
runtime
} from "@systemfsoftware/trigger.dev_core/v3";
import { ProdRuntimeManager } from "@systemfsoftware/trigger.dev_core/v3/prod";
__WORKER_SETUP__;
__IMPORTED_PROJECT_CONFIG__;
var heartbeatIntervalMs = getEnvVar("USAGE_HEARTBEAT_INTERVAL_MS");
var usageEventUrl = getEnvVar("USAGE_EVENT_URL");
var triggerJWT = getEnvVar("TRIGGER_JWT");
var prodUsageManager = new ProdUsageManager(new DevUsageManager(), {
heartbeatIntervalMs: heartbeatIntervalMs ? parseInt(heartbeatIntervalMs, 10) : void 0,
url: usageEventUrl,
jwt: triggerJWT
});
usage.setGlobalUsageManager(prodUsageManager);
var durableClock = new DurableClock();
clock.setGlobalClock(durableClock);
var tracer = new TriggerTracer({ tracer: otelTracer, logger: otelLogger });
var consoleInterceptor = new ConsoleInterceptor(otelLogger, true);
var triggerLogLevel = getEnvVar("TRIGGER_LOG_LEVEL");
var configLogLevel = triggerLogLevel ? triggerLogLevel : importedConfig ? importedConfig.logLevel : __PROJECT_CONFIG__.logLevel;
var otelTaskLogger = new OtelTaskLogger({
logger: otelLogger,
tracer,
level: logLevels.includes(configLogLevel) ? configLogLevel : "info"
});
logger.setGlobalTaskLogger(otelTaskLogger);
var TaskFileImports = {};
var TaskFiles = {};
__TASKS__;
(() => {
for (const [importName, taskFile] of Object.entries(TaskFiles)) {
const fileImports = TaskFileImports[importName];
for (const [exportName, task] of Object.entries(fileImports ?? {})) {
if (typeof task === "object" && task !== null && "id" in task && typeof task.id === "string") {
if (taskCatalog.taskExists(task.id)) {
taskCatalog.registerTaskFileMetadata(task.id, {
exportName,
filePath: taskFile.filePath
});
}
}
}
}
})();
var _execution;
var _isRunning = false;
var zodIpc = new ZodIpcConnection({
listenSchema: ProdWorkerToChildMessages,
emitSchema: ProdChildToWorkerMessages,
process,
handlers: {
EXECUTE_TASK_RUN: async ({ execution, traceContext, metadata }, sender) => {
if (_isRunning) {
console.error("Worker is already running a task");
await sender.send("TASK_RUN_COMPLETED", {
execution,
result: {
ok: false,
id: execution.run.id,
error: {
type: "INTERNAL_ERROR",
code: TaskRunErrorCodes.TASK_ALREADY_RUNNING
}
}
});
return;
}
process.title = `trigger-prod-worker: ${execution.task.id} ${execution.run.id}`;
const task = taskCatalog.getTask(execution.task.id);
if (!task) {
console.error(`Could not find task ${execution.task.id}`);
await sender.send("TASK_RUN_COMPLETED", {
execution,
result: {
ok: false,
id: execution.run.id,
error: {
type: "INTERNAL_ERROR",
code: TaskRunErrorCodes.COULD_NOT_FIND_EXECUTOR
}
}
});
return;
}
const executor = new TaskExecutor(task, {
tracer,
tracingSDK,
consoleInterceptor,
projectConfig: __PROJECT_CONFIG__,
importedConfig,
handleErrorFn: handleError
});
try {
_execution = execution;
_isRunning = true;
const measurement = usage.start();
const { result } = await executor.execute(execution, metadata, traceContext, measurement);
const usageSample = usage.stop(measurement);
return await sender.send("TASK_RUN_COMPLETED", {
execution,
result: {
...result,
usage: {
durationMs: usageSample.cpuTime
}
}
});
} finally {
_execution = void 0;
_isRunning = false;
}
},
TASK_RUN_COMPLETED_NOTIFICATION: async ({ completion }) => {
prodRuntimeManager.resumeTask(completion);
},
WAIT_COMPLETED_NOTIFICATION: async () => {
prodRuntimeManager.resumeAfterDuration();
},
CLEANUP: async ({ flush, kill }, sender) => {
if (kill) {
await flushAll();
await sender.send("READY_TO_DISPOSE", void 0);
} else {
if (flush) {
await flushAll();
}
}
}
}
});
async function flushAll(timeoutInMs = 1e4) {
const now = performance.now();
console.log(`Flushing at ${now}`);
await Promise.all([flushUsage(), flushTracingSDK()]);
const duration = performance.now() - now;
console.log(`Flushed in ${duration}ms`);
}
async function flushUsage() {
const now = performance.now();
console.log(`Flushing usage at ${now}`);
await prodUsageManager.flush();
const duration = performance.now() - now;
console.log(`Flushed usage in ${duration}ms`);
}
async function flushTracingSDK() {
const now = performance.now();
console.log(`Flushing tracingSDK at ${now}`);
await tracingSDK.flush();
const duration = performance.now() - now;
console.log(`Flushed tracingSDK in ${duration}ms`);
}
process.on("SIGTERM", async () => {
});
var prodRuntimeManager = new ProdRuntimeManager(zodIpc, {
waitThresholdInMs: parseInt(process.env.TRIGGER_RUNTIME_WAIT_THRESHOLD_IN_MS ?? "30000", 10)
});
runtime.setGlobalRuntimeManager(prodRuntimeManager);
var taskMetadata = taskCatalog.getAllTaskMetadata();
if (typeof importedConfig?.machine === "string") {
taskMetadata = taskMetadata.map((task) => {
if (typeof task.machine?.preset !== "string") {
return {
...task,
machine: {
preset: importedConfig.machine
}
};
}
return task;
});
}
zodIpc.send("TASKS_READY", { tasks: taskMetadata }).catch((err) => {
if (err instanceof ZodSchemaParsedError) {
zodIpc.send("TASKS_FAILED_TO_PARSE", { zodIssues: err.error.issues, tasks: taskMetadata });
} else {
console.error("Failed to send TASKS_READY message", err);
}
});
process.title = "trigger-prod-worker";
async function asyncHeartbeat(initialDelayInSeconds = 30, intervalInSeconds = 20) {
async function _doHeartbeat() {
while (true) {
if (_isRunning && _execution) {
try {
await zodIpc.send("TASK_HEARTBEAT", { id: _execution.attempt.id });
} catch (err) {
console.error("Failed to send HEARTBEAT message", err);
}
}
await new Promise((resolve) => setTimeout(resolve, 1e3 * intervalInSeconds));
}
}
await new Promise((resolve) => setTimeout(resolve, 1e3 * initialDelayInSeconds));
return _doHeartbeat();
}
asyncHeartbeat(5).catch((err) => {
console.error("Failed to start asyncHeartbeat", err);
});