more tests and fixes
This commit is contained in:
@@ -57,7 +57,7 @@ export class StandardLifecycleHooksManager implements LifecycleHooksManager {
|
||||
|
||||
this.globalStartHooks.set(id, {
|
||||
id,
|
||||
name: hook.id ?? hook.fn.name ? (hook.fn.name === "" ? undefined : hook.fn.name) : undefined,
|
||||
name: hook.id,
|
||||
fn: hook.fn,
|
||||
});
|
||||
}
|
||||
@@ -70,7 +70,7 @@ export class StandardLifecycleHooksManager implements LifecycleHooksManager {
|
||||
|
||||
this.taskStartHooks.set(taskId, {
|
||||
id,
|
||||
name: hook.id ?? hook.fn.name ? (hook.fn.name === "" ? undefined : hook.fn.name) : undefined,
|
||||
name: hook.id,
|
||||
fn: hook.fn,
|
||||
});
|
||||
}
|
||||
@@ -89,7 +89,7 @@ export class StandardLifecycleHooksManager implements LifecycleHooksManager {
|
||||
|
||||
const registeredHook = {
|
||||
id,
|
||||
name: hook.id ?? hook.fn.name ? (hook.fn.name === "" ? undefined : hook.fn.name) : undefined,
|
||||
name: hook.id,
|
||||
fn: hook.fn,
|
||||
};
|
||||
|
||||
@@ -122,7 +122,7 @@ export class StandardLifecycleHooksManager implements LifecycleHooksManager {
|
||||
|
||||
this.globalFailureHooks.set(id, {
|
||||
id,
|
||||
name: hook.id ?? hook.fn.name ? (hook.fn.name === "" ? undefined : hook.fn.name) : undefined,
|
||||
name: hook.id,
|
||||
fn: hook.fn,
|
||||
});
|
||||
}
|
||||
@@ -135,7 +135,7 @@ export class StandardLifecycleHooksManager implements LifecycleHooksManager {
|
||||
|
||||
this.taskFailureHooks.set(taskId, {
|
||||
id,
|
||||
name: hook.id ?? hook.fn.name ? (hook.fn.name === "" ? undefined : hook.fn.name) : undefined,
|
||||
name: hook.id,
|
||||
fn: hook.fn,
|
||||
});
|
||||
}
|
||||
@@ -153,7 +153,7 @@ export class StandardLifecycleHooksManager implements LifecycleHooksManager {
|
||||
|
||||
this.globalSuccessHooks.set(id, {
|
||||
id,
|
||||
name: hook.id ?? hook.fn.name ? (hook.fn.name === "" ? undefined : hook.fn.name) : undefined,
|
||||
name: hook.id,
|
||||
fn: hook.fn,
|
||||
});
|
||||
}
|
||||
@@ -166,7 +166,7 @@ export class StandardLifecycleHooksManager implements LifecycleHooksManager {
|
||||
|
||||
this.taskSuccessHooks.set(taskId, {
|
||||
id,
|
||||
name: hook.id ?? hook.fn.name ? (hook.fn.name === "" ? undefined : hook.fn.name) : undefined,
|
||||
name: hook.id,
|
||||
fn: hook.fn,
|
||||
});
|
||||
}
|
||||
@@ -184,7 +184,7 @@ export class StandardLifecycleHooksManager implements LifecycleHooksManager {
|
||||
|
||||
this.globalCompleteHooks.set(id, {
|
||||
id,
|
||||
name: hook.id ?? hook.fn.name ? (hook.fn.name === "" ? undefined : hook.fn.name) : undefined,
|
||||
name: hook.id,
|
||||
fn: hook.fn,
|
||||
});
|
||||
}
|
||||
@@ -197,7 +197,7 @@ export class StandardLifecycleHooksManager implements LifecycleHooksManager {
|
||||
|
||||
this.taskCompleteHooks.set(taskId, {
|
||||
id,
|
||||
name: hook.id ?? hook.fn.name ? (hook.fn.name === "" ? undefined : hook.fn.name) : undefined,
|
||||
name: hook.id,
|
||||
fn: hook.fn,
|
||||
});
|
||||
}
|
||||
@@ -215,7 +215,7 @@ export class StandardLifecycleHooksManager implements LifecycleHooksManager {
|
||||
|
||||
this.globalWaitHooks.set(id, {
|
||||
id,
|
||||
name: hook.id ?? hook.fn.name ? (hook.fn.name === "" ? undefined : hook.fn.name) : undefined,
|
||||
name: hook.id,
|
||||
fn: hook.fn,
|
||||
});
|
||||
}
|
||||
@@ -228,7 +228,7 @@ export class StandardLifecycleHooksManager implements LifecycleHooksManager {
|
||||
|
||||
this.taskWaitHooks.set(taskId, {
|
||||
id,
|
||||
name: hook.id ?? hook.fn.name ? (hook.fn.name === "" ? undefined : hook.fn.name) : undefined,
|
||||
name: hook.id,
|
||||
fn: hook.fn,
|
||||
});
|
||||
}
|
||||
@@ -246,7 +246,7 @@ export class StandardLifecycleHooksManager implements LifecycleHooksManager {
|
||||
|
||||
this.globalResumeHooks.set(id, {
|
||||
id,
|
||||
name: hook.id ?? hook.fn.name ? (hook.fn.name === "" ? undefined : hook.fn.name) : undefined,
|
||||
name: hook.id,
|
||||
fn: hook.fn,
|
||||
});
|
||||
}
|
||||
@@ -259,7 +259,7 @@ export class StandardLifecycleHooksManager implements LifecycleHooksManager {
|
||||
|
||||
this.taskResumeHooks.set(taskId, {
|
||||
id,
|
||||
name: hook.id ?? hook.fn.name ? (hook.fn.name === "" ? undefined : hook.fn.name) : undefined,
|
||||
name: hook.id,
|
||||
fn: hook.fn,
|
||||
});
|
||||
}
|
||||
@@ -279,7 +279,7 @@ export class StandardLifecycleHooksManager implements LifecycleHooksManager {
|
||||
|
||||
this.globalCatchErrorHooks.set(id, {
|
||||
id,
|
||||
name: hook.id ?? hook.fn.name ? (hook.fn.name === "" ? undefined : hook.fn.name) : undefined,
|
||||
name: hook.id,
|
||||
fn: hook.fn,
|
||||
});
|
||||
}
|
||||
@@ -292,7 +292,7 @@ export class StandardLifecycleHooksManager implements LifecycleHooksManager {
|
||||
|
||||
this.taskCatchErrorHooks.set(taskId, {
|
||||
id,
|
||||
name: hook.id ?? hook.fn.name ? (hook.fn.name === "" ? undefined : hook.fn.name) : undefined,
|
||||
name: hook.id,
|
||||
fn: hook.fn,
|
||||
});
|
||||
}
|
||||
@@ -312,7 +312,7 @@ export class StandardLifecycleHooksManager implements LifecycleHooksManager {
|
||||
|
||||
this.globalMiddlewareHooks.set(id, {
|
||||
id,
|
||||
name: hook.id ?? hook.fn.name ? (hook.fn.name === "" ? undefined : hook.fn.name) : undefined,
|
||||
name: hook.id,
|
||||
fn: hook.fn,
|
||||
});
|
||||
}
|
||||
@@ -325,7 +325,7 @@ export class StandardLifecycleHooksManager implements LifecycleHooksManager {
|
||||
|
||||
this.taskMiddlewareHooks.set(taskId, {
|
||||
id,
|
||||
name: hook.id ?? hook.fn.name ? (hook.fn.name === "" ? undefined : hook.fn.name) : undefined,
|
||||
name: hook.id,
|
||||
fn: hook.fn,
|
||||
});
|
||||
}
|
||||
@@ -507,9 +507,5 @@ export class NoopLifecycleHooksManager implements LifecycleHooksManager {
|
||||
}
|
||||
|
||||
function generateHookId(hook: RegisterHookFunctionParams<any>): string {
|
||||
return hook.id ?? hook.fn.name
|
||||
? hook.fn.name === ""
|
||||
? hook.fn.toString()
|
||||
: hook.fn.name
|
||||
: hook.fn.toString();
|
||||
return hook.id ?? hook.fn.toString();
|
||||
}
|
||||
|
||||
@@ -3,13 +3,8 @@ import { VERSION } from "../../version.js";
|
||||
import { ApiError, RateLimitError } from "../apiClient/errors.js";
|
||||
import { ConsoleInterceptor } from "../consoleInterceptor.js";
|
||||
import { isInternalError, parseError, sanitizeError, TaskPayloadParsedError } from "../errors.js";
|
||||
import {
|
||||
flattenAttributes,
|
||||
lifecycleHooks,
|
||||
runMetadata,
|
||||
TriggerConfig,
|
||||
waitUntil,
|
||||
} from "../index.js";
|
||||
import { flattenAttributes, lifecycleHooks, runMetadata, waitUntil } from "../index.js";
|
||||
import { TaskCompleteResult } from "../lifecycleHooks/types.js";
|
||||
import { recordSpanException, TracingSDK } from "../otel/index.js";
|
||||
import { runTimelineMetrics } from "../run-timeline-metrics-api.js";
|
||||
import {
|
||||
@@ -25,7 +20,6 @@ import { SemanticInternalAttributes } from "../semanticInternalAttributes.js";
|
||||
import { taskContext } from "../task-context-api.js";
|
||||
import { TriggerTracer } from "../tracer.js";
|
||||
import { HandleErrorFunction, TaskMetadataWithFunctions } from "../types/index.js";
|
||||
import { UsageMeasurement } from "../usage/types.js";
|
||||
import {
|
||||
conditionallyExportPacket,
|
||||
conditionallyImportPacket,
|
||||
@@ -34,7 +28,6 @@ import {
|
||||
stringifyIO,
|
||||
} from "../utils/ioSerialization.js";
|
||||
import { calculateNextRetryDelay } from "../utils/retries.js";
|
||||
import { TaskCompleteResult } from "../lifecycleHooks/types.js";
|
||||
|
||||
export type TaskExecutorOptions = {
|
||||
tracingSDK: TracingSDK;
|
||||
@@ -134,12 +127,12 @@ export class TaskExecutor {
|
||||
try {
|
||||
parsedPayload = await this.#parsePayload(parsedPayload);
|
||||
|
||||
if (execution.attempt.number === 1) {
|
||||
await this.#callOnStartFunctions(parsedPayload, ctx, signal);
|
||||
}
|
||||
|
||||
initOutput = await this.#callInitFunctions(parsedPayload, ctx, signal);
|
||||
|
||||
if (execution.attempt.number === 1) {
|
||||
await this.#callOnStartFunctions(parsedPayload, ctx, initOutput, signal);
|
||||
}
|
||||
|
||||
const output = await this.#callRun(parsedPayload, ctx, initOutput, signal);
|
||||
|
||||
try {
|
||||
@@ -573,7 +566,12 @@ export class TaskExecutor {
|
||||
}
|
||||
}
|
||||
|
||||
async #callOnStartFunctions(payload: unknown, ctx: TaskRunContext, signal?: AbortSignal) {
|
||||
async #callOnStartFunctions(
|
||||
payload: unknown,
|
||||
ctx: TaskRunContext,
|
||||
initOutput: any,
|
||||
signal?: AbortSignal
|
||||
) {
|
||||
const globalStartHooks = lifecycleHooks.getGlobalStartHooks();
|
||||
const taskStartHook = lifecycleHooks.getTaskStartHook(this.task.id);
|
||||
|
||||
@@ -592,7 +590,7 @@ export class TaskExecutor {
|
||||
await this._tracer.startActiveSpan(
|
||||
hook.name ?? "global",
|
||||
async (span) => {
|
||||
await hook.fn({ payload, ctx, signal, task: this.task.id });
|
||||
await hook.fn({ payload, ctx, signal, task: this.task.id, init: initOutput });
|
||||
},
|
||||
{
|
||||
attributes: {
|
||||
@@ -606,7 +604,13 @@ export class TaskExecutor {
|
||||
await this._tracer.startActiveSpan(
|
||||
"task",
|
||||
async (span) => {
|
||||
await taskStartHook({ payload, ctx, signal, task: this.task.id });
|
||||
await taskStartHook({
|
||||
payload,
|
||||
ctx,
|
||||
signal,
|
||||
task: this.task.id,
|
||||
init: initOutput,
|
||||
});
|
||||
},
|
||||
{
|
||||
attributes: {
|
||||
|
||||
@@ -89,7 +89,7 @@ describe("TaskExecutor", () => {
|
||||
run: {
|
||||
id: "test-run-id",
|
||||
payload: "{}",
|
||||
payloadType: "json",
|
||||
payloadType: "application/json",
|
||||
metadata: {},
|
||||
startedAt: new Date(),
|
||||
tags: [],
|
||||
@@ -261,7 +261,7 @@ describe("TaskExecutor", () => {
|
||||
run: {
|
||||
id: "test-run-id",
|
||||
payload: "{}",
|
||||
payloadType: "json",
|
||||
payloadType: "application/json",
|
||||
metadata: {},
|
||||
startedAt: new Date(),
|
||||
tags: [],
|
||||
@@ -340,4 +340,188 @@ describe("TaskExecutor", () => {
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
test("should call onStart hooks in correct order with proper data", async () => {
|
||||
const globalStartOrder: string[] = [];
|
||||
const startPayloads: any[] = [];
|
||||
const startInits: any[] = [];
|
||||
|
||||
// Register global init hook to provide init data
|
||||
lifecycleHooks.registerGlobalInitHook({
|
||||
id: "test-init",
|
||||
fn: async () => {
|
||||
return {
|
||||
foo: "bar",
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
// Register two global start hooks
|
||||
lifecycleHooks.registerGlobalStartHook({
|
||||
id: "global-start-1",
|
||||
fn: async ({ payload, ctx, init }) => {
|
||||
console.log("Executing global start hook 1");
|
||||
globalStartOrder.push("global-1");
|
||||
startPayloads.push(payload);
|
||||
startInits.push(init);
|
||||
},
|
||||
});
|
||||
|
||||
lifecycleHooks.registerGlobalStartHook({
|
||||
id: "global-start-2",
|
||||
fn: async ({ payload, ctx, init }) => {
|
||||
console.log("Executing global start hook 2");
|
||||
globalStartOrder.push("global-2");
|
||||
startPayloads.push(payload);
|
||||
startInits.push(init);
|
||||
},
|
||||
});
|
||||
|
||||
// Register task-specific start hook
|
||||
lifecycleHooks.registerTaskStartHook("test-task", {
|
||||
id: "task-start",
|
||||
fn: async ({ payload, ctx, init }) => {
|
||||
console.log("Executing task start hook");
|
||||
globalStartOrder.push("task");
|
||||
startPayloads.push(payload);
|
||||
startInits.push(init);
|
||||
},
|
||||
});
|
||||
|
||||
// Verify hooks are registered
|
||||
const globalHooks = lifecycleHooks.getGlobalStartHooks();
|
||||
console.log(
|
||||
"Registered global hooks:",
|
||||
globalHooks.map((h) => h.id)
|
||||
);
|
||||
const taskHook = lifecycleHooks.getTaskStartHook("test-task");
|
||||
console.log("Registered task hook:", taskHook ? "yes" : "no");
|
||||
|
||||
const task = {
|
||||
id: "test-task",
|
||||
fns: {
|
||||
run: async (payload: any, params: RunFnParams<any>) => {
|
||||
return {
|
||||
output: "test-output",
|
||||
init: params.init,
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const tracingSDK = new TracingSDK({
|
||||
url: "http://localhost:4318",
|
||||
});
|
||||
|
||||
const tracer = new TriggerTracer({
|
||||
name: "test-task",
|
||||
version: "1.0.0",
|
||||
tracer: tracingSDK.getTracer("test-task"),
|
||||
logger: tracingSDK.getLogger("test-task"),
|
||||
});
|
||||
|
||||
const consoleInterceptor = new ConsoleInterceptor(tracingSDK.getLogger("test-task"), false);
|
||||
|
||||
const executor = new TaskExecutor(task, {
|
||||
tracingSDK,
|
||||
tracer,
|
||||
consoleInterceptor,
|
||||
retries: {
|
||||
enabledInDev: false,
|
||||
default: {
|
||||
maxAttempts: 1,
|
||||
},
|
||||
},
|
||||
handleErrorFn: undefined,
|
||||
});
|
||||
|
||||
const execution: TaskRunExecution = {
|
||||
task: {
|
||||
id: "test-task",
|
||||
filePath: "test-task.ts",
|
||||
},
|
||||
attempt: {
|
||||
number: 1,
|
||||
startedAt: new Date(),
|
||||
id: "test-attempt-id",
|
||||
status: "success",
|
||||
backgroundWorkerId: "test-background-worker-id",
|
||||
backgroundWorkerTaskId: "test-background-worker-task-id",
|
||||
},
|
||||
run: {
|
||||
id: "test-run-id",
|
||||
payload: '{"test":"data"}',
|
||||
payloadType: "application/json",
|
||||
metadata: {},
|
||||
startedAt: new Date(),
|
||||
tags: [],
|
||||
isTest: false,
|
||||
createdAt: new Date(),
|
||||
durationMs: 0,
|
||||
costInCents: 0,
|
||||
baseCostInCents: 0,
|
||||
priority: 0,
|
||||
},
|
||||
machine: {
|
||||
name: "micro",
|
||||
cpu: 1,
|
||||
memory: 1,
|
||||
centsPerMs: 0,
|
||||
},
|
||||
queue: {
|
||||
name: "test-queue",
|
||||
id: "test-queue-id",
|
||||
},
|
||||
environment: {
|
||||
type: "PRODUCTION",
|
||||
id: "test-environment-id",
|
||||
slug: "test-environment-slug",
|
||||
},
|
||||
organization: {
|
||||
id: "test-organization-id",
|
||||
name: "test-organization-name",
|
||||
slug: "test-organization-slug",
|
||||
},
|
||||
project: {
|
||||
id: "test-project-id",
|
||||
name: "test-project-name",
|
||||
slug: "test-project-slug",
|
||||
ref: "test-project-ref",
|
||||
},
|
||||
};
|
||||
|
||||
const worker: ServerBackgroundWorker = {
|
||||
id: "test-background-worker-id",
|
||||
version: "1.0.0",
|
||||
contentHash: "test-content-hash",
|
||||
engine: "V2",
|
||||
};
|
||||
|
||||
const result = await executor.execute(execution, worker, {});
|
||||
|
||||
// Verify hooks were called in correct order
|
||||
expect(globalStartOrder).toEqual(["global-1", "global-2", "task"]);
|
||||
|
||||
// Verify each hook received the correct payload
|
||||
startPayloads.forEach((payload) => {
|
||||
expect(payload).toEqual({ test: "data" });
|
||||
});
|
||||
|
||||
console.log("startInits", startInits);
|
||||
|
||||
// Verify each hook received the correct init data
|
||||
startInits.forEach((init) => {
|
||||
expect(init).toEqual({ foo: "bar" });
|
||||
});
|
||||
|
||||
// Verify the final result
|
||||
expect(result).toEqual({
|
||||
result: {
|
||||
ok: true,
|
||||
id: "test-run-id",
|
||||
output: '{"json":{"output":"test-output","init":{"foo":"bar"}}}',
|
||||
outputType: "application/super+json",
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user