nvent 0.5.4 → 0.5.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/module.json +1 -1
- package/dist/module.mjs +127 -23
- package/dist/runtime/adapters/builtin/memory-store.d.ts +2 -1
- package/dist/runtime/adapters/builtin/memory-store.js +28 -4
- package/dist/runtime/adapters/factory.js +8 -7
- package/dist/runtime/adapters/interfaces/queue.d.ts +5 -0
- package/dist/runtime/adapters/interfaces/store.d.ts +3 -1
- package/dist/runtime/config/index.js +14 -1
- package/dist/runtime/config/types.d.ts +42 -0
- package/dist/runtime/events/types.d.ts +0 -1
- package/dist/runtime/events/utils/stallDetector.d.ts +13 -77
- package/dist/runtime/events/utils/stallDetector.js +8 -192
- package/dist/runtime/events/wiring/flowWiring.js +347 -109
- package/dist/runtime/events/wiring/registry.js +9 -1
- package/dist/runtime/events/wiring/triggerWiring.js +11 -1
- package/dist/runtime/nitro/plugins/02.workers.js +31 -2
- package/dist/runtime/nitro/routes/webhook.await.js +28 -6
- package/dist/runtime/nitro/routes/webhook.trigger.d.ts +17 -0
- package/dist/runtime/nitro/routes/webhook.trigger.js +9 -0
- package/dist/runtime/nitro/utils/awaitPatterns/event.js +58 -50
- package/dist/runtime/nitro/utils/awaitPatterns/schedule.js +6 -1
- package/dist/runtime/nitro/utils/awaitPatterns/time.d.ts +1 -1
- package/dist/runtime/nitro/utils/awaitPatterns/time.js +6 -2
- package/dist/runtime/nitro/utils/awaitPatterns/webhook.js +53 -45
- package/dist/runtime/nitro/utils/defineFunction.d.ts +2 -9
- package/dist/runtime/nitro/utils/defineFunction.js +1 -14
- package/dist/runtime/nitro/utils/defineFunctionConfig.d.ts +84 -16
- package/dist/runtime/nitro/utils/defineHooks.d.ts +64 -10
- package/dist/runtime/nitro/utils/defineHooks.js +3 -0
- package/dist/runtime/nitro/utils/useAwait.d.ts +12 -0
- package/dist/runtime/nitro/utils/useAwait.js +34 -4
- package/dist/runtime/nitro/utils/useFlow.d.ts +39 -48
- package/dist/runtime/nitro/utils/useFlow.js +53 -14
- package/dist/runtime/nitro/utils/useHookRegistry.d.ts +10 -4
- package/dist/runtime/nitro/utils/useTrigger.js +7 -16
- package/dist/runtime/scheduler/index.js +5 -1
- package/dist/runtime/scheduler/scheduler.d.ts +19 -0
- package/dist/runtime/scheduler/scheduler.js +184 -8
- package/dist/runtime/scheduler/types.d.ts +6 -0
- package/dist/runtime/worker/node/runner.d.ts +44 -2
- package/dist/runtime/worker/node/runner.js +45 -100
- package/dist/runtime/worker/system/awaitHandlers.d.ts +27 -0
- package/dist/runtime/worker/system/awaitHandlers.js +230 -0
- package/dist/runtime/worker/system/index.d.ts +24 -0
- package/dist/runtime/worker/system/index.js +39 -0
- package/package.json +1 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { defineNitroPlugin, $useWorkerHandlers, $useFunctionRegistry, useQueueAdapter, useHookRegistry } from "#imports";
|
|
2
2
|
import { createJobProcessor } from "../../worker/node/runner.js";
|
|
3
|
+
import { registerSystemHandlersOnQueue } from "../../worker/system/index.js";
|
|
3
4
|
export default defineNitroPlugin(async (nitroApp) => {
|
|
4
5
|
nitroApp.hooks.hook("close", async () => {
|
|
5
6
|
const queueAdapter = useQueueAdapter();
|
|
@@ -11,6 +12,7 @@ export default defineNitroPlugin(async (nitroApp) => {
|
|
|
11
12
|
const handlers = $useWorkerHandlers();
|
|
12
13
|
const registry = $useFunctionRegistry() || { workers: [] };
|
|
13
14
|
const registeredQueues = /* @__PURE__ */ new Set();
|
|
15
|
+
const queuesWithHooks = /* @__PURE__ */ new Set();
|
|
14
16
|
for (const entry of handlers) {
|
|
15
17
|
const { queue, id, handler, module } = entry;
|
|
16
18
|
const w = registry.workers.find((rw) => rw?.id === id || rw?.queue?.name === queue && rw?.absPath === entry.absPath);
|
|
@@ -20,7 +22,7 @@ export default defineNitroPlugin(async (nitroApp) => {
|
|
|
20
22
|
} else {
|
|
21
23
|
jobName = id.includes("/") ? id.split("/").pop() : id;
|
|
22
24
|
}
|
|
23
|
-
if (module
|
|
25
|
+
if (module) {
|
|
24
26
|
const hooks = {};
|
|
25
27
|
if (typeof module.onAwaitRegister === "function") {
|
|
26
28
|
hooks.onAwaitRegister = module.onAwaitRegister;
|
|
@@ -28,7 +30,10 @@ export default defineNitroPlugin(async (nitroApp) => {
|
|
|
28
30
|
if (typeof module.onAwaitResolve === "function") {
|
|
29
31
|
hooks.onAwaitResolve = module.onAwaitResolve;
|
|
30
32
|
}
|
|
31
|
-
if (
|
|
33
|
+
if (typeof module.onAwaitTimeout === "function") {
|
|
34
|
+
hooks.onAwaitTimeout = module.onAwaitTimeout;
|
|
35
|
+
}
|
|
36
|
+
if (Object.keys(hooks).length > 0 && w?.flow) {
|
|
32
37
|
const hookRegistry = useHookRegistry();
|
|
33
38
|
const flowNames = w.flow.names ? Array.isArray(w.flow.names) ? w.flow.names : [w.flow.names] : w.flow.name ? Array.isArray(w.flow.name) ? w.flow.name : [w.flow.name] : [];
|
|
34
39
|
for (const flowName of flowNames) {
|
|
@@ -36,6 +41,20 @@ export default defineNitroPlugin(async (nitroApp) => {
|
|
|
36
41
|
hookRegistry.register(flowName, jobName, hooks);
|
|
37
42
|
}
|
|
38
43
|
}
|
|
44
|
+
queuesWithHooks.add(queue);
|
|
45
|
+
}
|
|
46
|
+
if (w?.flow?.awaitBefore || w?.flow?.awaitAfter) {
|
|
47
|
+
queuesWithHooks.add(queue);
|
|
48
|
+
}
|
|
49
|
+
if (w?.flow?.role === "entry") {
|
|
50
|
+
const flowNames = w.flow.names ? Array.isArray(w.flow.names) ? w.flow.names : [w.flow.names] : w.flow.name ? Array.isArray(w.flow.name) ? w.flow.name : [w.flow.name] : [];
|
|
51
|
+
for (const flowName of flowNames) {
|
|
52
|
+
const flowRegistry = (registry?.flows || {})[flowName];
|
|
53
|
+
if (flowRegistry?.entry?.awaitBefore || flowRegistry?.entry?.awaitAfter) {
|
|
54
|
+
queuesWithHooks.add(queue);
|
|
55
|
+
break;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
39
58
|
}
|
|
40
59
|
}
|
|
41
60
|
if (typeof handler === "function") {
|
|
@@ -52,6 +71,16 @@ export default defineNitroPlugin(async (nitroApp) => {
|
|
|
52
71
|
registeredQueues.add(queue);
|
|
53
72
|
}
|
|
54
73
|
}
|
|
74
|
+
for (const queueName of queuesWithHooks) {
|
|
75
|
+
try {
|
|
76
|
+
const queueWorker = registry.workers.find((w) => w?.queue?.name === queueName);
|
|
77
|
+
const concurrency = queueWorker?.worker?.concurrency;
|
|
78
|
+
registerSystemHandlersOnQueue(queueName, concurrency);
|
|
79
|
+
registeredQueues.add(queueName);
|
|
80
|
+
} catch (err) {
|
|
81
|
+
console.error(`[nvent] Failed to register system handlers on queue ${queueName}:`, err);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
55
84
|
if (queueAdapter.startProcessingQueue) {
|
|
56
85
|
for (const queueName of Array.from(registeredQueues)) {
|
|
57
86
|
queueAdapter.startProcessingQueue(queueName);
|
|
@@ -30,8 +30,8 @@ export default defineEventHandler(async (event) => {
|
|
|
30
30
|
});
|
|
31
31
|
}
|
|
32
32
|
const status = flowEntry.metadata?.status;
|
|
33
|
-
if (status && status !== "running") {
|
|
34
|
-
logger.warn(`Flow is not running`, { flowName, runId, stepName, status });
|
|
33
|
+
if (status && status !== "running" && status !== "awaiting") {
|
|
34
|
+
logger.warn(`Flow is not running or awaiting`, { flowName, runId, stepName, status });
|
|
35
35
|
setResponseStatus(event, 410);
|
|
36
36
|
throw createError({
|
|
37
37
|
statusCode: 410,
|
|
@@ -39,9 +39,32 @@ export default defineEventHandler(async (event) => {
|
|
|
39
39
|
message: `This webhook is no longer valid because the flow is ${status}.`
|
|
40
40
|
});
|
|
41
41
|
}
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
42
|
+
const awaitingSteps = flowEntry.metadata?.awaitingSteps || {};
|
|
43
|
+
const awaitKeyBefore = `${stepName}:before`;
|
|
44
|
+
const awaitKeyAfter = `${stepName}:after`;
|
|
45
|
+
let awaitState = null;
|
|
46
|
+
let position = "before";
|
|
47
|
+
const awaitStateBefore = awaitingSteps[awaitKeyBefore];
|
|
48
|
+
if (awaitStateBefore && awaitStateBefore.status === "awaiting") {
|
|
49
|
+
awaitState = awaitStateBefore;
|
|
50
|
+
position = "before";
|
|
51
|
+
}
|
|
52
|
+
if (!awaitState) {
|
|
53
|
+
const awaitStateAfter = awaitingSteps[awaitKeyAfter];
|
|
54
|
+
if (awaitStateAfter && awaitStateAfter.status === "awaiting") {
|
|
55
|
+
awaitState = awaitStateAfter;
|
|
56
|
+
position = "after";
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
if (!awaitState) {
|
|
60
|
+
const legacyAwaitState = awaitingSteps[stepName];
|
|
61
|
+
if (legacyAwaitState && legacyAwaitState.status === "awaiting") {
|
|
62
|
+
awaitState = legacyAwaitState;
|
|
63
|
+
position = "after";
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
if (!awaitState) {
|
|
67
|
+
logger.warn(`Step is not awaiting`, { flowName, runId, stepName, awaitingSteps });
|
|
45
68
|
setResponseStatus(event, 410);
|
|
46
69
|
throw createError({
|
|
47
70
|
statusCode: 410,
|
|
@@ -66,7 +89,6 @@ export default defineEventHandler(async (event) => {
|
|
|
66
89
|
message: `This webhook expects ${expectedMethod} requests.`
|
|
67
90
|
});
|
|
68
91
|
}
|
|
69
|
-
const position = awaitState.position || "after";
|
|
70
92
|
let webhookData;
|
|
71
93
|
if (event.method === "GET") {
|
|
72
94
|
webhookData = getRouterParams(event, { decode: true });
|
|
@@ -16,6 +16,7 @@ declare const _default: import("h3").EventHandler<import("h3").EventHandlerReque
|
|
|
16
16
|
triggerName?: undefined;
|
|
17
17
|
expectedType?: undefined;
|
|
18
18
|
actualType?: undefined;
|
|
19
|
+
status?: undefined;
|
|
19
20
|
expectedMethod?: undefined;
|
|
20
21
|
actualMethod?: undefined;
|
|
21
22
|
success?: undefined;
|
|
@@ -27,6 +28,7 @@ declare const _default: import("h3").EventHandler<import("h3").EventHandlerReque
|
|
|
27
28
|
message: string;
|
|
28
29
|
expectedType?: undefined;
|
|
29
30
|
actualType?: undefined;
|
|
31
|
+
status?: undefined;
|
|
30
32
|
expectedMethod?: undefined;
|
|
31
33
|
actualMethod?: undefined;
|
|
32
34
|
success?: undefined;
|
|
@@ -38,6 +40,19 @@ declare const _default: import("h3").EventHandler<import("h3").EventHandlerReque
|
|
|
38
40
|
expectedType: string;
|
|
39
41
|
actualType: any;
|
|
40
42
|
message?: undefined;
|
|
43
|
+
status?: undefined;
|
|
44
|
+
expectedMethod?: undefined;
|
|
45
|
+
actualMethod?: undefined;
|
|
46
|
+
success?: undefined;
|
|
47
|
+
subscribedFlows?: undefined;
|
|
48
|
+
timestamp?: undefined;
|
|
49
|
+
} | {
|
|
50
|
+
error: string;
|
|
51
|
+
triggerName: string;
|
|
52
|
+
status: any;
|
|
53
|
+
message: string;
|
|
54
|
+
expectedType?: undefined;
|
|
55
|
+
actualType?: undefined;
|
|
41
56
|
expectedMethod?: undefined;
|
|
42
57
|
actualMethod?: undefined;
|
|
43
58
|
success?: undefined;
|
|
@@ -51,6 +66,7 @@ declare const _default: import("h3").EventHandler<import("h3").EventHandlerReque
|
|
|
51
66
|
triggerName?: undefined;
|
|
52
67
|
expectedType?: undefined;
|
|
53
68
|
actualType?: undefined;
|
|
69
|
+
status?: undefined;
|
|
54
70
|
success?: undefined;
|
|
55
71
|
subscribedFlows?: undefined;
|
|
56
72
|
timestamp?: undefined;
|
|
@@ -63,6 +79,7 @@ declare const _default: import("h3").EventHandler<import("h3").EventHandlerReque
|
|
|
63
79
|
error?: undefined;
|
|
64
80
|
expectedType?: undefined;
|
|
65
81
|
actualType?: undefined;
|
|
82
|
+
status?: undefined;
|
|
66
83
|
expectedMethod?: undefined;
|
|
67
84
|
actualMethod?: undefined;
|
|
68
85
|
}>>;
|
|
@@ -30,6 +30,15 @@ export default defineEventHandler(async (event) => {
|
|
|
30
30
|
actualType: triggerEntry.type
|
|
31
31
|
};
|
|
32
32
|
}
|
|
33
|
+
if (triggerEntry.status !== "active") {
|
|
34
|
+
logger.info(`Trigger '${triggerName}' is ${triggerEntry.status}, rejecting webhook`);
|
|
35
|
+
return {
|
|
36
|
+
error: "Trigger not active",
|
|
37
|
+
triggerName,
|
|
38
|
+
status: triggerEntry.status,
|
|
39
|
+
message: `Trigger '${triggerName}' is ${triggerEntry.status}. Update status to 'active' to enable.`
|
|
40
|
+
};
|
|
41
|
+
}
|
|
33
42
|
const expectedMethod = triggerEntry.webhook?.method || "POST";
|
|
34
43
|
if (event.method !== expectedMethod) {
|
|
35
44
|
logger.warn(`Method mismatch: expected ${expectedMethod}, got ${event.method}`);
|
|
@@ -18,6 +18,9 @@ export async function registerEventAwait(runId, stepName, flowName, config, posi
|
|
|
18
18
|
await resolveEventAwait(runId, stepName, flowName, position, event.data);
|
|
19
19
|
unsubscribe();
|
|
20
20
|
});
|
|
21
|
+
const { useAwaitDefaults } = await import("../useAwait.js");
|
|
22
|
+
const { eventTimeout: defaultTimeout, timeoutAction: defaultTimeoutAction } = useAwaitDefaults();
|
|
23
|
+
const timeoutMs = config.timeout && config.timeout > 0 ? config.timeout : defaultTimeout;
|
|
21
24
|
eventBus.publish({
|
|
22
25
|
type: "await.registered",
|
|
23
26
|
flowName,
|
|
@@ -27,66 +30,69 @@ export async function registerEventAwait(runId, stepName, flowName, config, posi
|
|
|
27
30
|
position,
|
|
28
31
|
config,
|
|
29
32
|
data: {
|
|
33
|
+
position,
|
|
34
|
+
// Store position in data for database persistence
|
|
30
35
|
eventName: config.event,
|
|
31
36
|
filterKey: config.filterKey,
|
|
32
|
-
timeout:
|
|
33
|
-
|
|
37
|
+
timeout: timeoutMs,
|
|
38
|
+
// Store resolved timeout (with default)
|
|
39
|
+
registeredAt: Date.now(),
|
|
40
|
+
timeoutAction: config.timeoutAction || defaultTimeoutAction
|
|
34
41
|
}
|
|
35
42
|
});
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
logger.warn("Event await timeout", {
|
|
47
|
-
runId,
|
|
48
|
-
stepName,
|
|
49
|
-
flowName,
|
|
50
|
-
eventName: config.event,
|
|
51
|
-
timeout: config.timeout,
|
|
52
|
-
timeoutAction: config.timeoutAction || "fail"
|
|
53
|
-
});
|
|
54
|
-
eventBus.publish({
|
|
55
|
-
type: "await.timeout",
|
|
56
|
-
flowName,
|
|
57
|
-
runId,
|
|
58
|
-
stepName,
|
|
59
|
-
position,
|
|
60
|
-
awaitType: "event",
|
|
61
|
-
timeoutAction: config.timeoutAction || "fail",
|
|
62
|
-
data: {
|
|
63
|
-
eventName: config.event,
|
|
64
|
-
timeout: config.timeout,
|
|
65
|
-
registeredAt: Date.now() - (config.timeout || 0),
|
|
66
|
-
timedOutAt: Date.now()
|
|
67
|
-
}
|
|
68
|
-
});
|
|
69
|
-
unsubscribe();
|
|
70
|
-
},
|
|
71
|
-
metadata: {
|
|
72
|
-
component: "await-pattern",
|
|
73
|
-
awaitType: "event",
|
|
43
|
+
const scheduler = useScheduler();
|
|
44
|
+
const timeoutAt = Date.now() + timeoutMs;
|
|
45
|
+
const jobId = `await-event-timeout-${runId}-${stepName}-${position}`;
|
|
46
|
+
await scheduler.schedule({
|
|
47
|
+
id: jobId,
|
|
48
|
+
name: `Event Await Timeout: ${flowName} - ${stepName}`,
|
|
49
|
+
type: "one-time",
|
|
50
|
+
executeAt: timeoutAt,
|
|
51
|
+
handler: async () => {
|
|
52
|
+
logger.warn("Event await timeout", {
|
|
74
53
|
runId,
|
|
75
54
|
stepName,
|
|
76
55
|
flowName,
|
|
56
|
+
eventName: config.event,
|
|
57
|
+
timeout: timeoutMs,
|
|
58
|
+
timeoutAction: config.timeoutAction || "fail"
|
|
59
|
+
});
|
|
60
|
+
eventBus.publish({
|
|
61
|
+
type: "await.timeout",
|
|
62
|
+
flowName,
|
|
63
|
+
runId,
|
|
64
|
+
stepName,
|
|
77
65
|
position,
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
66
|
+
awaitType: "event",
|
|
67
|
+
timeoutAction: config.timeoutAction || "fail",
|
|
68
|
+
data: {
|
|
69
|
+
eventName: config.event,
|
|
70
|
+
timeout: timeoutMs,
|
|
71
|
+
registeredAt: Date.now() - timeoutMs,
|
|
72
|
+
timedOutAt: Date.now()
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
unsubscribe();
|
|
76
|
+
},
|
|
77
|
+
metadata: {
|
|
78
|
+
component: "await-pattern",
|
|
79
|
+
awaitType: "event",
|
|
83
80
|
runId,
|
|
84
81
|
stepName,
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
82
|
+
flowName,
|
|
83
|
+
position,
|
|
84
|
+
timeout: timeoutMs,
|
|
85
|
+
eventName: config.event
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
logger.debug(`Event timeout scheduled`, {
|
|
89
|
+
runId,
|
|
90
|
+
stepName,
|
|
91
|
+
eventName: config.event,
|
|
92
|
+
timeout: timeoutMs,
|
|
93
|
+
timeoutAction: config.timeoutAction,
|
|
94
|
+
isDefault: !config.timeout || config.timeout <= 0
|
|
95
|
+
});
|
|
90
96
|
logger.debug(`Event await registered: ${config.event}`, { runId, stepName });
|
|
91
97
|
return {
|
|
92
98
|
eventName: config.event,
|
|
@@ -113,6 +119,8 @@ export async function resolveEventAwait(runId, stepName, flowName, position, eve
|
|
|
113
119
|
position,
|
|
114
120
|
triggerData: eventData,
|
|
115
121
|
data: {
|
|
122
|
+
position,
|
|
123
|
+
// Store position in data for database persistence
|
|
116
124
|
resolvedAt: Date.now()
|
|
117
125
|
}
|
|
118
126
|
});
|
|
@@ -43,6 +43,8 @@ export async function registerScheduleAwait(runId, stepName, flowName, config, p
|
|
|
43
43
|
position,
|
|
44
44
|
config,
|
|
45
45
|
data: {
|
|
46
|
+
position,
|
|
47
|
+
// Store position in data for database persistence
|
|
46
48
|
cron: config.cron,
|
|
47
49
|
nextOccurrence,
|
|
48
50
|
timeUntilNext,
|
|
@@ -63,14 +65,17 @@ export async function resolveScheduleAwait(runId, stepName, flowName, position,
|
|
|
63
65
|
const logger = useNventLogger("await-schedule");
|
|
64
66
|
const eventBus = getEventBus();
|
|
65
67
|
logger.info(`Resolving schedule await`, { runId, stepName });
|
|
68
|
+
const scheduledAt = scheduleData?.scheduledAt || Date.now();
|
|
66
69
|
eventBus.publish({
|
|
67
70
|
type: "await.resolved",
|
|
68
71
|
flowName,
|
|
69
72
|
runId,
|
|
70
73
|
stepName,
|
|
71
74
|
position,
|
|
72
|
-
triggerData:
|
|
75
|
+
triggerData: { scheduledAt },
|
|
73
76
|
data: {
|
|
77
|
+
position,
|
|
78
|
+
// Store position in data for database persistence
|
|
74
79
|
resolvedAt: Date.now()
|
|
75
80
|
}
|
|
76
81
|
});
|
|
@@ -12,4 +12,4 @@ export declare function registerTimeAwait(runId: string, stepName: string, flowN
|
|
|
12
12
|
/**
|
|
13
13
|
* Resolve time await when delay completes
|
|
14
14
|
*/
|
|
15
|
-
export declare function resolveTimeAwait(runId: string, stepName: string, flowName: string, position: 'before' | 'after',
|
|
15
|
+
export declare function resolveTimeAwait(runId: string, stepName: string, flowName: string, position: 'before' | 'after', _timeData: any): Promise<void>;
|
|
@@ -37,6 +37,8 @@ export async function registerTimeAwait(runId, stepName, flowName, config, posit
|
|
|
37
37
|
position,
|
|
38
38
|
config,
|
|
39
39
|
data: {
|
|
40
|
+
position,
|
|
41
|
+
// Store position in data for database persistence
|
|
40
42
|
delay: config.delay,
|
|
41
43
|
resolveAt,
|
|
42
44
|
registeredAt: Date.now()
|
|
@@ -48,7 +50,7 @@ export async function registerTimeAwait(runId, stepName, flowName, config, posit
|
|
|
48
50
|
resolveAt
|
|
49
51
|
};
|
|
50
52
|
}
|
|
51
|
-
export async function resolveTimeAwait(runId, stepName, flowName, position,
|
|
53
|
+
export async function resolveTimeAwait(runId, stepName, flowName, position, _timeData) {
|
|
52
54
|
const logger = useNventLogger("await-time");
|
|
53
55
|
const eventBus = getEventBus();
|
|
54
56
|
logger.info(`Resolving time await`, { runId, stepName });
|
|
@@ -58,8 +60,10 @@ export async function resolveTimeAwait(runId, stepName, flowName, position, time
|
|
|
58
60
|
runId,
|
|
59
61
|
stepName,
|
|
60
62
|
position,
|
|
61
|
-
triggerData:
|
|
63
|
+
triggerData: {},
|
|
62
64
|
data: {
|
|
65
|
+
position,
|
|
66
|
+
// Store position in data for database persistence
|
|
63
67
|
resolvedAt: Date.now()
|
|
64
68
|
}
|
|
65
69
|
});
|
|
@@ -22,6 +22,9 @@ export async function registerWebhookAwait(runId, stepName, flowName, config, po
|
|
|
22
22
|
const webhookPath = `/api/_webhook/await${path}`;
|
|
23
23
|
const fullWebhookUrl = `${baseUrl.replace(/\/$/, "")}${webhookPath}`;
|
|
24
24
|
logger.info(`Registering webhook await: ${fullWebhookUrl}`, { runId, stepName });
|
|
25
|
+
const { useAwaitDefaults } = await import("../useAwait.js");
|
|
26
|
+
const { webhookTimeout: defaultTimeout, timeoutAction: defaultTimeoutAction } = useAwaitDefaults();
|
|
27
|
+
const timeoutMs = config.timeout && config.timeout > 0 ? config.timeout : defaultTimeout;
|
|
25
28
|
eventBus.publish({
|
|
26
29
|
type: "await.registered",
|
|
27
30
|
flowName,
|
|
@@ -31,62 +34,65 @@ export async function registerWebhookAwait(runId, stepName, flowName, config, po
|
|
|
31
34
|
position,
|
|
32
35
|
config,
|
|
33
36
|
data: {
|
|
37
|
+
position,
|
|
38
|
+
// Store position in data for database persistence
|
|
34
39
|
path,
|
|
35
40
|
method: config.method || "POST",
|
|
36
|
-
timeout:
|
|
41
|
+
timeout: timeoutMs,
|
|
42
|
+
// Store resolved timeout (with default)
|
|
37
43
|
registeredAt: Date.now(),
|
|
38
|
-
webhookUrl: fullWebhookUrl
|
|
44
|
+
webhookUrl: fullWebhookUrl,
|
|
45
|
+
timeoutAction: config.timeoutAction || defaultTimeoutAction
|
|
39
46
|
}
|
|
40
47
|
});
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
logger.warn("Webhook await timeout", {
|
|
52
|
-
runId,
|
|
53
|
-
stepName,
|
|
54
|
-
flowName,
|
|
55
|
-
timeout: config.timeout,
|
|
56
|
-
timeoutAction: config.timeoutAction || "fail"
|
|
57
|
-
});
|
|
58
|
-
eventBus.publish({
|
|
59
|
-
type: "await.timeout",
|
|
60
|
-
flowName,
|
|
61
|
-
runId,
|
|
62
|
-
stepName,
|
|
63
|
-
position,
|
|
64
|
-
awaitType: "webhook",
|
|
65
|
-
timeoutAction: config.timeoutAction || "fail",
|
|
66
|
-
data: {
|
|
67
|
-
timeout: config.timeout,
|
|
68
|
-
registeredAt: Date.now() - (config.timeout || 0),
|
|
69
|
-
timedOutAt: Date.now()
|
|
70
|
-
}
|
|
71
|
-
});
|
|
72
|
-
},
|
|
73
|
-
metadata: {
|
|
74
|
-
component: "await-pattern",
|
|
75
|
-
awaitType: "webhook",
|
|
48
|
+
const scheduler = useScheduler();
|
|
49
|
+
const timeoutAt = Date.now() + timeoutMs;
|
|
50
|
+
const jobId = `await-webhook-timeout-${runId}-${stepName}-${position}`;
|
|
51
|
+
await scheduler.schedule({
|
|
52
|
+
id: jobId,
|
|
53
|
+
name: `Webhook Timeout: ${flowName} - ${stepName}`,
|
|
54
|
+
type: "one-time",
|
|
55
|
+
executeAt: timeoutAt,
|
|
56
|
+
handler: async () => {
|
|
57
|
+
logger.warn("Webhook await timeout", {
|
|
76
58
|
runId,
|
|
77
59
|
stepName,
|
|
78
60
|
flowName,
|
|
61
|
+
timeout: timeoutMs,
|
|
62
|
+
timeoutAction: config.timeoutAction || "fail"
|
|
63
|
+
});
|
|
64
|
+
eventBus.publish({
|
|
65
|
+
type: "await.timeout",
|
|
66
|
+
flowName,
|
|
67
|
+
runId,
|
|
68
|
+
stepName,
|
|
79
69
|
position,
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
70
|
+
awaitType: "webhook",
|
|
71
|
+
timeoutAction: config.timeoutAction || "fail",
|
|
72
|
+
data: {
|
|
73
|
+
timeout: timeoutMs,
|
|
74
|
+
registeredAt: Date.now() - timeoutMs,
|
|
75
|
+
timedOutAt: Date.now()
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
},
|
|
79
|
+
metadata: {
|
|
80
|
+
component: "await-pattern",
|
|
81
|
+
awaitType: "webhook",
|
|
84
82
|
runId,
|
|
85
83
|
stepName,
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
84
|
+
flowName,
|
|
85
|
+
position,
|
|
86
|
+
timeout: timeoutMs
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
logger.debug(`Webhook timeout scheduled`, {
|
|
90
|
+
runId,
|
|
91
|
+
stepName,
|
|
92
|
+
timeout: timeoutMs,
|
|
93
|
+
timeoutAction: config.timeoutAction,
|
|
94
|
+
isDefault: !config.timeout || config.timeout <= 0
|
|
95
|
+
});
|
|
90
96
|
logger.debug(`Webhook await registered: ${fullWebhookUrl}`, { runId, stepName });
|
|
91
97
|
return {
|
|
92
98
|
webhookUrl: fullWebhookUrl,
|
|
@@ -113,6 +119,8 @@ export async function resolveWebhookAwait(runId, stepName, flowName, position, w
|
|
|
113
119
|
position,
|
|
114
120
|
triggerData: webhookData,
|
|
115
121
|
data: {
|
|
122
|
+
position,
|
|
123
|
+
// Store position in data for database persistence
|
|
116
124
|
resolvedAt: Date.now()
|
|
117
125
|
}
|
|
118
126
|
});
|
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
export type ExtendedRunContext = RunContext & {
|
|
4
|
-
provider: ReturnType<typeof useQueueAdapter>;
|
|
5
|
-
flow: ReturnType<typeof useFlow>;
|
|
6
|
-
registry: any;
|
|
7
|
-
};
|
|
8
|
-
export type DefineFunction = (handler: (input: any, ctx: ExtendedRunContext) => Promise<any>) => NodeHandler;
|
|
9
|
-
export declare const defineFunction: DefineFunction;
|
|
1
|
+
import type { RunContext, NodeHandler } from '../../worker/node/runner.js';
|
|
2
|
+
export declare const defineFunction: <TInput = any, TOutput = any>(handler: (input: TInput, ctx: RunContext) => Promise<TOutput>) => NodeHandler;
|
|
10
3
|
export default defineFunction;
|
|
@@ -1,17 +1,4 @@
|
|
|
1
|
-
import { $useFunctionRegistry, useFlow, useQueueAdapter } from "#imports";
|
|
2
1
|
export const defineFunction = (handler) => {
|
|
3
|
-
|
|
4
|
-
const provider = useQueueAdapter();
|
|
5
|
-
const flow = ctx.flow || useFlow();
|
|
6
|
-
const registry = $useFunctionRegistry();
|
|
7
|
-
const extended = {
|
|
8
|
-
...ctx,
|
|
9
|
-
provider,
|
|
10
|
-
flow,
|
|
11
|
-
registry
|
|
12
|
-
};
|
|
13
|
-
return handler(input, extended);
|
|
14
|
-
};
|
|
15
|
-
return wrapped;
|
|
2
|
+
return handler;
|
|
16
3
|
};
|
|
17
4
|
export default defineFunction;
|