Skip to content

Commit 94cc38f

Browse files
committed
Revamping the lifecycle hooks, starting with init
1 parent c4e1364 commit 94cc38f

File tree

15 files changed

+318
-32
lines changed

15 files changed

+318
-32
lines changed

packages/cli-v3/src/entryPoints/dev-run-worker.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ import {
1818
WorkerManifest,
1919
WorkerToExecutorMessageCatalog,
2020
runTimelineMetrics,
21+
lifecycleHooks,
22+
lifecycleHooksAdapters,
2123
} from "@trigger.dev/core/v3";
2224
import { TriggerTracer } from "@trigger.dev/core/v3/tracer";
2325
import {
@@ -38,6 +40,7 @@ import {
3840
usage,
3941
UsageTimeoutManager,
4042
StandardRunTimelineMetricsManager,
43+
StandardLifecycleHooksManager,
4144
} from "@trigger.dev/core/v3/workers";
4245
import { ZodIpcConnection } from "@trigger.dev/core/v3/zodIpc";
4346
import { readFile } from "node:fs/promises";
@@ -93,6 +96,9 @@ const standardRunTimelineMetricsManager = new StandardRunTimelineMetricsManager(
9396
runTimelineMetrics.setGlobalManager(standardRunTimelineMetricsManager);
9497
standardRunTimelineMetricsManager.seedMetricsFromEnvironment();
9598

99+
const standardLifecycleHooksManager = new StandardLifecycleHooksManager();
100+
lifecycleHooks.setGlobalLifecycleHooksManager(standardLifecycleHooksManager);
101+
96102
const devUsageManager = new DevUsageManager();
97103
usage.setGlobalUsageManager(devUsageManager);
98104
timeout.setGlobalManager(new UsageTimeoutManager(devUsageManager));
@@ -170,6 +176,13 @@ async function bootstrap() {
170176

171177
logger.setGlobalTaskLogger(otelTaskLogger);
172178

179+
if (config.init) {
180+
lifecycleHooks.registerGlobalInitHook({
181+
id: "trigger-dev-worker",
182+
fn: lifecycleHooksAdapters.createInitHookAdapter(config.init),
183+
});
184+
}
185+
173186
return {
174187
tracer,
175188
tracingSDK,

packages/core/src/v3/config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ export type TriggerConfig = {
216216
/**
217217
* Run before a task is executed, for all tasks. This is useful for setting up any global state that is needed for all tasks.
218218
*/
219-
init?: (payload: unknown, params: InitFnParams) => void | Promise<void>;
219+
init?: (payload: unknown, params: InitFnParams) => any | Promise<any>;
220220

221221
/**
222222
* onSuccess is called after the run function has successfully completed.

packages/core/src/v3/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export * from "./run-metadata-api.js";
1515
export * from "./wait-until-api.js";
1616
export * from "./timeout-api.js";
1717
export * from "./run-timeline-metrics-api.js";
18+
export * from "./lifecycle-hooks-api.js";
1819
export * from "./schemas/index.js";
1920
export { SemanticInternalAttributes } from "./semanticInternalAttributes.js";
2021
export * from "./resource-catalog-api.js";
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Split module-level variable definition into separate files to allow
2+
// tree-shaking on each api instance.
3+
import { LifecycleHooksAPI } from "./lifecycleHooks/index.js";
4+
/** Entrypoint for runtime API */
5+
export const lifecycleHooks = LifecycleHooksAPI.getInstance();
6+
7+
export type {
8+
OnInitHookFunction,
9+
AnyOnInitHookFunction,
10+
RegisteredHookFunction,
11+
} from "./lifecycleHooks/types.js";
12+
13+
export * as lifecycleHooksAdapters from "./lifecycleHooks/adapters.js";
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { TaskOptions } from "../types/index.js";
2+
import { AnyOnInitHookFunction } from "./types.js";
3+
4+
export function createInitHookAdapter<TPayload>(
5+
fn: NonNullable<TaskOptions<string, TPayload, unknown, any>["init"]>
6+
): AnyOnInitHookFunction {
7+
return async (params) => {
8+
const paramsWithoutPayload = {
9+
...params,
10+
};
11+
12+
delete paramsWithoutPayload["payload"];
13+
14+
return await fn(params.payload as unknown as TPayload, paramsWithoutPayload);
15+
};
16+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
const API_NAME = "lifecycle-hooks";
2+
3+
import { getGlobal, registerGlobal, unregisterGlobal } from "../utils/globals.js";
4+
import { NoopLifecycleHooksManager } from "./manager.js";
5+
import {
6+
AnyOnInitHookFunction,
7+
RegisteredHookFunction,
8+
RegisterHookFunctionParams,
9+
type LifecycleHooksManager,
10+
} from "./types.js";
11+
12+
const NOOP_LIFECYCLE_HOOKS_MANAGER = new NoopLifecycleHooksManager();
13+
14+
export class LifecycleHooksAPI {
15+
private static _instance?: LifecycleHooksAPI;
16+
17+
private constructor() {}
18+
19+
public static getInstance(): LifecycleHooksAPI {
20+
if (!this._instance) {
21+
this._instance = new LifecycleHooksAPI();
22+
}
23+
24+
return this._instance;
25+
}
26+
27+
public setGlobalLifecycleHooksManager(lifecycleHooksManager: LifecycleHooksManager): boolean {
28+
return registerGlobal(API_NAME, lifecycleHooksManager);
29+
}
30+
31+
public disable() {
32+
unregisterGlobal(API_NAME);
33+
}
34+
35+
public registerGlobalInitHook(hook: RegisterHookFunctionParams<AnyOnInitHookFunction>): void {
36+
this.#getManager().registerGlobalInitHook(hook);
37+
}
38+
39+
public registerTaskInitHook(
40+
taskId: string,
41+
hook: RegisterHookFunctionParams<AnyOnInitHookFunction>
42+
): void {
43+
this.#getManager().registerTaskInitHook(taskId, hook);
44+
}
45+
46+
public getTaskInitHook(taskId: string): AnyOnInitHookFunction | undefined {
47+
return this.#getManager().getTaskInitHook(taskId);
48+
}
49+
50+
public getGlobalInitHooks(): RegisteredHookFunction<AnyOnInitHookFunction>[] {
51+
return this.#getManager().getGlobalInitHooks();
52+
}
53+
54+
#getManager(): LifecycleHooksManager {
55+
return getGlobal(API_NAME) ?? NOOP_LIFECYCLE_HOOKS_MANAGER;
56+
}
57+
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import {
2+
AnyOnInitHookFunction,
3+
LifecycleHooksManager,
4+
RegisteredHookFunction,
5+
RegisterHookFunctionParams,
6+
} from "./types.js";
7+
8+
export class StandardLifecycleHooksManager implements LifecycleHooksManager {
9+
private initHooks: Map<string, RegisteredHookFunction<AnyOnInitHookFunction>> = new Map();
10+
private taskInitHooks: Map<string, string> = new Map();
11+
12+
registerGlobalInitHook(hook: RegisterHookFunctionParams<AnyOnInitHookFunction>): void {
13+
// if there is no id, lets generate one based on the contents of the function
14+
const id = generateHookId(hook);
15+
16+
const registeredHook = {
17+
id,
18+
name: hook.id ?? hook.fn.name,
19+
fn: hook.fn,
20+
};
21+
22+
this.initHooks.set(id, registeredHook);
23+
}
24+
25+
registerTaskInitHook(
26+
taskId: string,
27+
hook: RegisterHookFunctionParams<AnyOnInitHookFunction>
28+
): void {
29+
const registeredHook = {
30+
id: generateHookId(hook),
31+
name: taskId,
32+
fn: hook.fn,
33+
};
34+
35+
this.initHooks.set(registeredHook.id, registeredHook);
36+
this.taskInitHooks.set(taskId, registeredHook.id);
37+
}
38+
39+
getTaskInitHook(taskId: string): AnyOnInitHookFunction | undefined {
40+
const hookId = this.taskInitHooks.get(taskId);
41+
if (!hookId) return undefined;
42+
return this.initHooks.get(hookId)?.fn;
43+
}
44+
45+
getGlobalInitHooks(): RegisteredHookFunction<AnyOnInitHookFunction>[] {
46+
return Array.from(this.initHooks.values());
47+
}
48+
}
49+
50+
export class NoopLifecycleHooksManager implements LifecycleHooksManager {
51+
registerGlobalInitHook(hook: RegisterHookFunctionParams<AnyOnInitHookFunction>): void {
52+
// Noop
53+
}
54+
55+
registerTaskInitHook(
56+
taskId: string,
57+
hook: RegisterHookFunctionParams<AnyOnInitHookFunction>
58+
): void {
59+
// Noop
60+
}
61+
62+
getTaskInitHook(taskId: string): AnyOnInitHookFunction | undefined {
63+
return undefined;
64+
}
65+
66+
getGlobalInitHooks(): RegisteredHookFunction<AnyOnInitHookFunction>[] {
67+
return [];
68+
}
69+
}
70+
71+
function generateHookId(hook: RegisterHookFunctionParams<any>): string {
72+
return hook.id ?? hook.fn.name ?? hook.fn.toString();
73+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { TaskRunContext } from "../schemas/index.js";
2+
3+
export type OnInitHookFunction<TPayload, TInitOutput> = (params: {
4+
ctx: TaskRunContext;
5+
payload: TPayload;
6+
task: string;
7+
signal?: AbortSignal;
8+
}) => TInitOutput | undefined | void | Promise<TInitOutput | undefined | void>;
9+
10+
export type AnyOnInitHookFunction = OnInitHookFunction<unknown, unknown>;
11+
12+
export type RegisterHookFunctionParams<THookFunction extends (params: any) => any> = {
13+
id?: string;
14+
fn: THookFunction;
15+
};
16+
17+
export type RegisteredHookFunction<THookFunction extends (params: any) => any> = {
18+
id: string;
19+
name?: string;
20+
fn: THookFunction;
21+
};
22+
23+
export interface LifecycleHooksManager {
24+
registerGlobalInitHook(hook: RegisterHookFunctionParams<AnyOnInitHookFunction>): void;
25+
registerTaskInitHook(
26+
taskId: string,
27+
hook: RegisterHookFunctionParams<AnyOnInitHookFunction>
28+
): void;
29+
getTaskInitHook(taskId: string): AnyOnInitHookFunction | undefined;
30+
getGlobalInitHooks(): RegisteredHookFunction<AnyOnInitHookFunction>[];
31+
}

packages/core/src/v3/utils/globals.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { ApiClientConfiguration } from "../apiClientManager/types.js";
22
import { Clock } from "../clock/clock.js";
3+
import { LifecycleHooksManager } from "../lifecycleHooks/types.js";
34
import { ResourceCatalog } from "../resource-catalog/catalog.js";
45
import { RunMetadataManager } from "../runMetadata/types.js";
56
import type { RuntimeManager } from "../runtime/manager.js";
@@ -62,4 +63,5 @@ type TriggerDotDevGlobalAPI = {
6263
["timeout"]?: TimeoutManager;
6364
["wait-until"]?: WaitUntilManager;
6465
["run-timeline-metrics"]?: RunTimelineMetricsManager;
66+
["lifecycle-hooks"]?: LifecycleHooksManager;
6567
};

packages/core/src/v3/workers/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,4 @@ export { ManagedRuntimeManager } from "../runtime/managedRuntimeManager.js";
2020
export * from "../runEngineWorker/index.js";
2121
export { StandardRunTimelineMetricsManager } from "../runTimelineMetrics/runTimelineMetricsManager.js";
2222
export { WarmStartClient, type WarmStartClientOptions } from "../workers/warmStartClient.js";
23+
export { StandardLifecycleHooksManager } from "../lifecycleHooks/manager.js";

0 commit comments

Comments
 (0)