bringing back the background worker stuff

This commit is contained in:
Eric Allam
2024-08-07 22:23:29 +01:00
committed by Eric Allam
parent 5bc482e3bc
commit 98046c58ae
19 changed files with 1489 additions and 77 deletions
+2 -4
View File
@@ -21,11 +21,9 @@ import {
import { zodfetch, ApiError } from "@trigger.dev/core/v3/zodfetch";
export class CliApiClient {
private readonly apiURL: string;
constructor(
apiURL: string,
private readonly accessToken?: string
public readonly apiURL: string,
public readonly accessToken?: string
) {
this.apiURL = apiURL.replace(/\/$/, "");
}
+1
View File
@@ -152,6 +152,7 @@ async function startDev(options: StartDevOptions) {
initialMode="local"
showInteractiveDevSession={true}
client={projectClient.client}
dashboardUrl={options.login.dashboardUrl}
/>
);
}
File diff suppressed because it is too large Load Diff
+18 -1
View File
@@ -21,9 +21,11 @@ import { type DevCommandOptions } from "../commands/dev.js";
import { logger } from "../utilities/logger.js";
import { EphemeralDirectory, getTmpDir } from "../utilities/tempDirectories.js";
import { copyManifestToDir } from "../build/manifests.js";
import { startWorkerRuntime } from "./workerRuntime.js";
export type DevSessionOptions = {
name: string | undefined;
dashboardUrl: string;
initialMode: "local";
showInteractiveDevSession: boolean | undefined;
rawConfig: ResolvedConfig;
@@ -31,9 +33,23 @@ export type DevSessionOptions = {
client: CliApiClient;
};
export async function startDevSession({ rawConfig }: DevSessionOptions) {
export async function startDevSession({
rawConfig,
name,
rawArgs,
client,
dashboardUrl,
}: DevSessionOptions) {
const destination = getTmpDir(rawConfig.workingDir, "build");
const runtime = await startWorkerRuntime({
name,
config: rawConfig,
args: rawArgs,
client,
dashboardUrl,
});
logger.debug("Starting dev session", { destination: destination.path, rawConfig });
const externalsExtension = createExternalsBuildExtension("dev", rawConfig);
@@ -124,6 +140,7 @@ export async function startDevSession({ rawConfig }: DevSessionOptions) {
destination.remove();
stopBundling?.().catch((error) => {});
runtime.shutdown().catch((error) => {});
},
};
}
+103
View File
@@ -0,0 +1,103 @@
import { z } from "zod";
export class UncaughtExceptionError extends Error {
constructor(
public readonly originalError: { name: string; message: string; stack?: string },
public readonly origin: "uncaughtException" | "unhandledRejection"
) {
super(`Uncaught exception: ${originalError.message}`);
this.name = "UncaughtExceptionError";
}
}
export class TaskMetadataParseError extends Error {
constructor(
public readonly zodIssues: z.ZodIssue[],
public readonly tasks: any
) {
super(`Failed to parse task metadata`);
this.name = "TaskMetadataParseError";
}
}
export class UnexpectedExitError extends Error {
constructor(
public code: number,
public signal: NodeJS.Signals | null,
public stderr: string | undefined
) {
super(`Unexpected exit with code ${code}`);
this.name = "UnexpectedExitError";
}
}
export class CleanupProcessError extends Error {
constructor() {
super("Cancelled");
this.name = "CleanupProcessError";
}
}
export class CancelledProcessError extends Error {
constructor() {
super("Cancelled");
this.name = "CancelledProcessError";
}
}
export class SigKillTimeoutProcessError extends Error {
constructor() {
super("Process kill timeout");
this.name = "SigKillTimeoutProcessError";
}
}
export class GracefulExitTimeoutError extends Error {
constructor() {
super("Graceful exit timeout");
this.name = "GracefulExitTimeoutError";
}
}
export function getFriendlyErrorMessage(
code: number,
signal: NodeJS.Signals | null,
stderr: string | undefined,
dockerMode = true
) {
const message = (text: string) => {
if (signal) {
return `[${signal}] ${text}`;
} else {
return text;
}
};
if (code === 137) {
if (dockerMode) {
return message(
"Process ran out of memory! Try choosing a machine preset with more memory for this task."
);
} else {
// Note: containerState reason and message should be checked to clarify the error
return message(
"Process most likely ran out of memory, but we can't be certain. Try choosing a machine preset with more memory for this task."
);
}
}
if (stderr?.includes("OOMErrorHandler")) {
return message(
"Process ran out of memory! Try choosing a machine preset with more memory for this task."
);
}
return message(`Process exited with code ${code}.`);
}
+272
View File
@@ -0,0 +1,272 @@
import {
BuildManifest,
clientWebsocketMessages,
SemanticInternalAttributes,
serverWebsocketMessages,
TaskRunExecutionLazyAttemptPayload,
} from "@trigger.dev/core/v3";
import { ResolvedConfig } from "@trigger.dev/core/v3/build";
import { ClientRequestArgs } from "node:http";
import { WebSocket } from "partysocket";
import { ClientOptions, WebSocket as wsWebSocket } from "ws";
import { CliApiClient } from "../apiClient.js";
import { DevCommandOptions } from "../commands/dev.js";
import { chalkError } from "../utilities/cliOutput.js";
import { logger } from "../utilities/logger.js";
import { BackgroundWorker, BackgroundWorkerCoordinator } from "./backgroundWorker.js";
import {
MessagePayloadFromSchema,
ZodMessageHandler,
ZodMessageSender,
} from "@trigger.dev/core/v3/zodMessageHandler";
import { resolveDotEnvVars } from "../utilities/dotEnv.js";
export interface WorkerRuntime {
shutdown(): Promise<void>;
initializeWorker(manifest: BuildManifest): Promise<void>;
}
export type WorkerRuntimeOptions = {
name: string | undefined;
config: ResolvedConfig;
args: DevCommandOptions;
client: CliApiClient;
dashboardUrl: string;
};
export async function startWorkerRuntime(options: WorkerRuntimeOptions): Promise<WorkerRuntime> {
const runtime = new DevWorkerRuntime(options);
await runtime.init();
return runtime;
}
class DevWorkerRuntime implements WorkerRuntime {
private websocket: WebSocket;
private backgroundWorkerCoordinator: BackgroundWorkerCoordinator;
private sender: ZodMessageSender<typeof clientWebsocketMessages>;
private websocketMessageHandler: ZodMessageHandler<typeof serverWebsocketMessages>;
constructor(public readonly options: WorkerRuntimeOptions) {
const websocketUrl = new URL(this.options.client.apiURL);
websocketUrl.protocol = websocketUrl.protocol.replace("http", "ws");
websocketUrl.pathname = `/ws`;
this.sender = new ZodMessageSender({
schema: clientWebsocketMessages,
sender: async (message) => {
this.websocket.send(JSON.stringify(message));
},
});
this.backgroundWorkerCoordinator = new BackgroundWorkerCoordinator(
`${options.dashboardUrl}/projects/v3/${options.config.project}`
);
this.backgroundWorkerCoordinator.onWorkerTaskRunHeartbeat.attach(
async ({ worker, backgroundWorkerId, id }) => {
await this.sender.send("BACKGROUND_WORKER_MESSAGE", {
backgroundWorkerId,
data: {
type: "TASK_RUN_HEARTBEAT",
id,
},
});
}
);
this.backgroundWorkerCoordinator.onTaskCompleted.attach(
async ({ backgroundWorkerId, completion, execution }) => {
await this.sender.send("BACKGROUND_WORKER_MESSAGE", {
backgroundWorkerId,
data: {
type: "TASK_RUN_COMPLETED",
completion,
execution,
},
});
}
);
this.backgroundWorkerCoordinator.onTaskFailedToRun.attach(
async ({ backgroundWorkerId, completion }) => {
await this.sender.send("BACKGROUND_WORKER_MESSAGE", {
backgroundWorkerId,
data: {
type: "TASK_RUN_FAILED_TO_RUN",
completion,
},
});
}
);
this.backgroundWorkerCoordinator.onWorkerRegistered.attach(async ({ id, worker, record }) => {
await this.sender.send("READY_FOR_TASKS", {
backgroundWorkerId: id,
});
});
this.websocketMessageHandler = new ZodMessageHandler({
schema: serverWebsocketMessages,
messages: {
SERVER_READY: async (payload) => {
await this.#serverReady(payload);
},
BACKGROUND_WORKER_MESSAGE: async (payload) => {
await this.#backgroundWorkerMessage(payload);
},
},
});
this.websocket = new WebSocket(websocketUrl.href, [], {
WebSocket: WebsocketFactory(this.options.client.accessToken!),
connectionTimeout: 10000,
maxRetries: 10,
minReconnectionDelay: 1000,
maxReconnectionDelay: 30000,
reconnectionDelayGrowFactor: 1.4, // This leads to the following retry times: 1, 1.4, 1.96, 2.74, 3.84, 5.38, 7.53, 10.54, 14.76, 20.66
maxEnqueuedMessages: 250,
});
this.websocket.addEventListener("open", async (event) => {
logger.debug("WebSocket opened", { event });
});
this.websocket.addEventListener("close", (event) => {
logger.debug("WebSocket closed", { event });
});
this.websocket.addEventListener("error", (event) => {
logger.log(`${chalkError("WebSocketError:")} ${event.error.message}`);
});
this.websocket.addEventListener("message", this.#handleWebsocketMessage.bind(this));
}
async init(): Promise<void> {}
async shutdown(): Promise<void> {
this.websocket.close();
}
async initializeWorker(manifest: BuildManifest, options?: { cwd?: string }): Promise<void> {
const env = await this.#getEnvVars();
const backgroundWorker = new BackgroundWorker(manifest, {
env,
cwd: this.options.config.workingDir,
});
await backgroundWorker.initialize();
}
async #getEnvVars(): Promise<Record<string, string>> {
const environmentVariablesResponse = await this.options.client.getEnvironmentVariables(
this.options.config.project
);
const processEnv = gatherProcessEnv();
const dotEnvVars = resolveDotEnvVars();
return {
...processEnv,
...(environmentVariablesResponse.success ? environmentVariablesResponse.data.variables : {}),
...dotEnvVars,
TRIGGER_API_URL: this.options.client.apiURL,
TRIGGER_SECRET_KEY: this.options.client.accessToken!,
OTEL_EXPORTER_OTLP_COMPRESSION: "none",
OTEL_RESOURCE_ATTRIBUTES: JSON.stringify({
[SemanticInternalAttributes.PROJECT_DIR]: this.options.config.workingDir,
}),
};
}
async #handleWebsocketMessage(event: MessageEvent) {
try {
const data = JSON.parse(
typeof event.data === "string" ? event.data : new TextDecoder("utf-8").decode(event.data)
);
await this.websocketMessageHandler.handleMessage(data);
} catch (error) {
if (error instanceof Error) {
logger.error("Error while handling websocket message", { error: error.message });
} else {
logger.error(
"Unkown error while handling websocket message, use `-l debug` for additional output"
);
logger.debug("Error while handling websocket message", { error });
}
}
}
async #serverReady(
payload: MessagePayloadFromSchema<"SERVER_READY", typeof serverWebsocketMessages>
) {
for (const worker of this.backgroundWorkerCoordinator.currentWorkers) {
await this.sender.send("READY_FOR_TASKS", {
backgroundWorkerId: worker.id,
inProgressRuns: worker.worker.inProgressRuns,
});
}
}
async #backgroundWorkerMessage(
payload: MessagePayloadFromSchema<"BACKGROUND_WORKER_MESSAGE", typeof serverWebsocketMessages>
) {
const message = payload.data;
logger.debug(
`Received message from worker ${payload.backgroundWorkerId}`,
JSON.stringify({ workerMessage: message })
);
switch (message.type) {
case "CANCEL_ATTEMPT": {
// Need to cancel the attempt somehow here
this.backgroundWorkerCoordinator.cancelRun(payload.backgroundWorkerId, message.taskRunId);
break;
}
case "EXECUTE_RUN_LAZY_ATTEMPT": {
await this.#executeTaskRunLazyAttempt(payload.backgroundWorkerId, message.payload);
}
}
}
async #executeTaskRunLazyAttempt(id: string, payload: TaskRunExecutionLazyAttemptPayload) {
const attemptResponse = await this.options.client.createTaskRunAttempt(payload.runId);
if (!attemptResponse.success) {
throw new Error(`Failed to create task run attempt: ${attemptResponse.error}`);
}
const execution = attemptResponse.data;
const completion = await this.backgroundWorkerCoordinator.executeTaskRun(
id,
{ execution, traceContext: payload.traceContext, environment: payload.environment },
payload.messageId
);
return { execution, completion };
}
}
function WebsocketFactory(apiKey: string) {
return class extends wsWebSocket {
constructor(address: string | URL, options?: ClientOptions | ClientRequestArgs) {
super(address, { ...(options ?? {}), headers: { Authorization: `Bearer ${apiKey}` } });
}
};
}
function gatherProcessEnv() {
const env = {
...process.env,
NODE_ENV: "development",
};
// Filter out undefined values
return Object.fromEntries(Object.entries(env).filter(([key, value]) => value !== undefined));
}
+21
View File
@@ -0,0 +1,21 @@
import dotenv from "dotenv";
import { resolve } from "node:path";
export function resolveDotEnvVars(cwd?: string) {
const result: { [key: string]: string } = {};
dotenv.config({
processEnv: result,
path: [".env", ".env.local", ".env.development.local"].map((p) =>
resolve(cwd ?? process.cwd(), p)
),
});
process.env.TRIGGER_API_URL && (result.TRIGGER_API_URL = process.env.TRIGGER_API_URL);
// remove TRIGGER_API_URL and TRIGGER_SECRET_KEY, since those should be coming from the worker
delete result.TRIGGER_API_URL;
delete result.TRIGGER_SECRET_KEY;
return result;
}
+1 -15
View File
@@ -1,12 +1,6 @@
import { z } from "zod";
import { ConfigManifest } from "./config.js";
export const TaskFile = z.object({
entry: z.string(),
out: z.string(),
});
export type TaskFile = z.infer<typeof TaskFile>;
import { TaskFile, TaskManifest } from "./schemas.js";
export const BuildExternal = z.object({
name: z.string(),
@@ -53,14 +47,6 @@ export const IndexMessage = z.object({
export type IndexMessage = z.infer<typeof IndexMessage>;
export const TaskManifest = z.object({
id: z.string(),
exportName: z.string(),
file: TaskFile,
});
export type TaskManifest = z.infer<typeof TaskManifest>;
export const WorkerManifest = z.object({
tasks: TaskManifest.array(),
});
+9 -12
View File
@@ -9,18 +9,15 @@ import {
EnvironmentType,
ProdTaskRunExecution,
ProdTaskRunExecutionPayload,
TaskMetadataWithFilePath,
TaskManifest,
TaskRunExecutionLazyAttemptPayload,
TaskRunExecutionPayload,
WaitReason,
} from "./schemas.js";
import { TaskResource } from "./resources.js";
import { WorkerManifest } from "./build.js";
export const BackgroundWorkerServerMessages = z.discriminatedUnion("type", [
z.object({
type: z.literal("EXECUTE_RUNS"),
payloads: z.array(TaskRunExecutionPayload),
}),
z.object({
type: z.literal("CANCEL_ATTEMPT"),
taskAttemptId: z.string(),
@@ -86,13 +83,13 @@ export const BackgroundWorkerClientMessages = z.discriminatedUnion("type", [
export type BackgroundWorkerClientMessages = z.infer<typeof BackgroundWorkerClientMessages>;
export const BackgroundWorkerProperties = z.object({
export const ServerBackgroundWorker = z.object({
id: z.string(),
version: z.string(),
contentHash: z.string(),
});
export type BackgroundWorkerProperties = z.infer<typeof BackgroundWorkerProperties>;
export type ServerBackgroundWorker = z.infer<typeof ServerBackgroundWorker>;
export const clientWebsocketMessages = {
READY_FOR_TASKS: z.object({
@@ -116,7 +113,7 @@ export const workerToChildMessages = {
version: z.literal("v1").default("v1"),
execution: TaskRunExecution,
traceContext: z.record(z.unknown()),
metadata: BackgroundWorkerProperties,
metadata: ServerBackgroundWorker,
}),
TASK_RUN_COMPLETED_NOTIFICATION: z.discriminatedUnion("version", [
z.object({
@@ -160,9 +157,9 @@ export const childToWorkerMessages = {
execution: TaskRunExecution,
result: TaskRunExecutionResult,
}),
TASKS_READY: z.object({
INDEX_COMPLETE: z.object({
version: z.literal("v1").default("v1"),
tasks: TaskMetadataWithFilePath.array(),
manifest: WorkerManifest,
}),
TASKS_FAILED_TO_PARSE: TaskMetadataFailedToParseData,
TASK_HEARTBEAT: z.object({
@@ -201,7 +198,7 @@ export const ProdChildToWorkerMessages = {
TASKS_READY: {
message: z.object({
version: z.literal("v1").default("v1"),
tasks: TaskMetadataWithFilePath.array(),
tasks: TaskManifest.array(),
}),
},
TASKS_FAILED_TO_PARSE: {
@@ -248,7 +245,7 @@ export const ProdWorkerToChildMessages = {
version: z.literal("v1").default("v1"),
execution: TaskRunExecution,
traceContext: z.record(z.unknown()),
metadata: BackgroundWorkerProperties,
metadata: ServerBackgroundWorker,
}),
},
TASK_RUN_COMPLETED_NOTIFICATION: {
+20 -17
View File
@@ -147,38 +147,41 @@ export const ScheduleMetadata = z.object({
timezone: z.string(),
});
export const TaskMetadata = z.object({
const taskMetadata = {
id: z.string(),
packageVersion: z.string(),
queue: QueueOptions.optional(),
retry: RetryOptions.optional(),
machine: MachineConfig.optional(),
triggerSource: z.string().optional(),
schedule: ScheduleMetadata.optional(),
});
};
export const TaskMetadata = z.object(taskMetadata);
export type TaskMetadata = z.infer<typeof TaskMetadata>;
export const TaskFileMetadata = z.object({
filePath: z.string(),
exportName: z.string(),
export const TaskFile = z.object({
entry: z.string(),
out: z.string(),
});
export type TaskFile = z.infer<typeof TaskFile>;
const taskFileMetadata = {
file: TaskFile,
exportName: z.string(),
};
export const TaskFileMetadata = z.object(taskFileMetadata);
export type TaskFileMetadata = z.infer<typeof TaskFileMetadata>;
export const TaskMetadataWithFilePath = z.object({
id: z.string(),
packageVersion: z.string(),
queue: QueueOptions.optional(),
retry: RetryOptions.optional(),
machine: MachineConfig.optional(),
triggerSource: z.string().optional(),
schedule: ScheduleMetadata.optional(),
filePath: z.string(),
exportName: z.string(),
export const TaskManifest = z.object({
...taskMetadata,
...taskFileMetadata,
});
export type TaskMetadataWithFilePath = z.infer<typeof TaskMetadataWithFilePath>;
export type TaskManifest = z.infer<typeof TaskManifest>;
export const PostStartCauses = z.enum(["index", "create", "restore"]);
export type PostStartCauses = z.infer<typeof PostStartCauses>;
+3 -3
View File
@@ -1,12 +1,12 @@
import { TaskFileMetadata, TaskMetadataWithFilePath } from "../schemas/index.js";
import { TaskFileMetadata, TaskManifest } from "../schemas/index.js";
import { TaskMetadataWithFunctions } from "../types/index.js";
export interface TaskCatalog {
registerTaskMetadata(task: TaskMetadataWithFunctions): void;
updateTaskMetadata(id: string, task: Partial<TaskMetadataWithFunctions>): void;
registerTaskFileMetadata(id: string, metadata: TaskFileMetadata): void;
getAllTaskMetadata(): Array<TaskMetadataWithFilePath>;
getTaskMetadata(id: string): TaskMetadataWithFilePath | undefined;
listTaskManifests(): Array<TaskManifest>;
getTaskManifest(id: string): TaskManifest | undefined;
getTask(id: string): TaskMetadataWithFunctions | undefined;
taskExists(id: string): boolean;
}
+5 -5
View File
@@ -1,6 +1,6 @@
const API_NAME = "task-catalog";
import { TaskFileMetadata, TaskMetadataWithFilePath } from "../schemas/index.js";
import { TaskFileMetadata, TaskManifest } from "../schemas/index.js";
import { TaskMetadataWithFunctions } from "../types/index.js";
import { getGlobal, registerGlobal, unregisterGlobal } from "../utils/globals.js";
import { type TaskCatalog } from "./catalog.js";
@@ -41,12 +41,12 @@ export class TaskCatalogAPI {
this.#getCatalog().registerTaskFileMetadata(id, metadata);
}
public getAllTaskMetadata(): Array<TaskMetadataWithFilePath> {
return this.#getCatalog().getAllTaskMetadata();
public listTaskManifests(): Array<TaskManifest> {
return this.#getCatalog().listTaskManifests();
}
public getTaskMetadata(id: string): TaskMetadataWithFilePath | undefined {
return this.#getCatalog().getTaskMetadata(id);
public getTaskManifest(id: string): TaskManifest | undefined {
return this.#getCatalog().getTaskManifest(id);
}
public getTask(id: string): TaskMetadataWithFunctions | undefined {
@@ -1,4 +1,4 @@
import { TaskFileMetadata, TaskMetadataWithFilePath } from "../schemas/index.js";
import { TaskFileMetadata, TaskManifest } from "../schemas/index.js";
import { TaskMetadataWithFunctions } from "../types/index.js";
import { TaskCatalog } from "./catalog.js";
@@ -15,11 +15,11 @@ export class NoopTaskCatalog implements TaskCatalog {
// noop
}
getAllTaskMetadata(): Array<TaskMetadataWithFilePath> {
listTaskManifests(): Array<TaskManifest> {
return [];
}
getTaskMetadata(id: string): TaskMetadataWithFilePath | undefined {
getTaskManifest(id: string): TaskManifest | undefined {
return undefined;
}
@@ -1,4 +1,4 @@
import { TaskFileMetadata, TaskMetadata, TaskMetadataWithFilePath } from "../schemas/index.js";
import { TaskFileMetadata, TaskMetadata, TaskManifest } from "../schemas/index.js";
import { TaskMetadataWithFunctions } from "../types/index.js";
import { TaskCatalog } from "./catalog.js";
@@ -45,8 +45,8 @@ export class StandardTaskCatalog implements TaskCatalog {
}
// Return all the tasks, without the functions
getAllTaskMetadata(): Array<TaskMetadataWithFilePath> {
const result: Array<TaskMetadataWithFilePath> = [];
listTaskManifests(): Array<TaskManifest> {
const result: Array<TaskManifest> = [];
for (const [id, metadata] of this._taskMetadata) {
const fileMetadata = this._taskFileMetadata.get(id);
@@ -64,7 +64,7 @@ export class StandardTaskCatalog implements TaskCatalog {
return result;
}
getTaskMetadata(id: string): TaskMetadataWithFilePath | undefined {
getTaskManifest(id: string): TaskManifest | undefined {
const metadata = this._taskMetadata.get(id);
const fileMetadata = this._taskFileMetadata.get(id);
+2 -2
View File
@@ -1,5 +1,5 @@
import { Attributes } from "@opentelemetry/api";
import { BackgroundWorkerProperties, TaskRunContext } from "../schemas/index.js";
import { ServerBackgroundWorker, TaskRunContext } from "../schemas/index.js";
import { getGlobal, registerGlobal, unregisterGlobal } from "../utils/globals.js";
import { TaskContext } from "./types.js";
import { SemanticInternalAttributes } from "../semanticInternalAttributes.js";
@@ -27,7 +27,7 @@ export class TaskContextAPI {
return this.#getTaskContext()?.ctx;
}
get worker(): BackgroundWorkerProperties | undefined {
get worker(): ServerBackgroundWorker | undefined {
return this.#getTaskContext()?.worker;
}
+2 -2
View File
@@ -1,6 +1,6 @@
import { BackgroundWorkerProperties, TaskRunContext } from "../schemas/index.js";
import { ServerBackgroundWorker, TaskRunContext } from "../schemas/index.js";
export type TaskContext = {
ctx: TaskRunContext;
worker: BackgroundWorkerProperties;
worker: ServerBackgroundWorker;
};
+1 -6
View File
@@ -1,9 +1,4 @@
import {
RetryOptions,
TaskMetadata,
TaskMetadataWithFilePath,
TaskRunContext,
} from "../schemas/index.js";
import { RetryOptions, TaskMetadata, TaskManifest, TaskRunContext } from "../schemas/index.js";
import { Prettify } from "./utils.js";
export * from "./utils.js";
+4 -3
View File
@@ -3,7 +3,7 @@ import { ConsoleInterceptor } from "../consoleInterceptor.js";
import { parseError, sanitizeError } from "../errors.js";
import { TracingSDK, recordSpanException } from "../otel/index.js";
import {
BackgroundWorkerProperties,
ServerBackgroundWorker,
Config,
TaskRunContext,
TaskRunErrorCodes,
@@ -27,6 +27,7 @@ import { accessoryAttributes } from "../utils/styleAttributes.js";
import { UsageMeasurement } from "../usage/types.js";
import { ApiError, RateLimitError } from "../apiClient/errors.js";
import { TriggerConfig } from "../index.js";
import { pkg } from "../../pkg.js";
export type TaskExecutorOptions = {
tracingSDK: TracingSDK;
@@ -59,7 +60,7 @@ export class TaskExecutor {
async execute(
execution: TaskRunExecution,
worker: BackgroundWorkerProperties,
worker: ServerBackgroundWorker,
traceContext: Record<string, unknown>,
usage: UsageMeasurement
): Promise<{ result: TaskRunExecutionResult }> {
@@ -78,7 +79,7 @@ export class TaskExecutor {
this._tracingSDK.asyncResourceDetector.resolveWithAttributes({
...taskContext.attributes,
[SemanticInternalAttributes.SDK_VERSION]: this.task.packageVersion,
[SemanticInternalAttributes.SDK_VERSION]: pkg.version,
[SemanticInternalAttributes.SDK_LANGUAGE]: "typescript",
});
@@ -36,6 +36,11 @@ export type MessageFromSchema<
payload: z.input<TMessageCatalog[K]>;
};
export type MessagePayloadFromSchema<
K extends keyof TMessageCatalog,
TMessageCatalog extends ZodMessageCatalogSchema,
> = z.output<TMessageCatalog[K]>;
export type MessageFromCatalog<TMessageCatalog extends ZodMessageCatalogSchema> = {
[K in keyof TMessageCatalog]: MessageFromSchema<K, TMessageCatalog>;
}[keyof TMessageCatalog];