nvent 0.5.3 → 0.5.5

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.
Files changed (36) hide show
  1. package/dist/module.json +1 -1
  2. package/dist/module.mjs +110 -24
  3. package/dist/runtime/adapters/factory.js +8 -7
  4. package/dist/runtime/adapters/interfaces/queue.d.ts +5 -0
  5. package/dist/runtime/config/index.js +14 -1
  6. package/dist/runtime/config/types.d.ts +42 -0
  7. package/dist/runtime/events/types.d.ts +0 -1
  8. package/dist/runtime/events/utils/stallDetector.d.ts +13 -77
  9. package/dist/runtime/events/utils/stallDetector.js +8 -192
  10. package/dist/runtime/events/wiring/flowWiring.js +311 -107
  11. package/dist/runtime/events/wiring/triggerWiring.js +3 -1
  12. package/dist/runtime/nitro/plugins/02.workers.js +31 -2
  13. package/dist/runtime/nitro/routes/webhook.await.js +28 -6
  14. package/dist/runtime/nitro/utils/awaitPatterns/event.js +58 -50
  15. package/dist/runtime/nitro/utils/awaitPatterns/schedule.js +6 -1
  16. package/dist/runtime/nitro/utils/awaitPatterns/time.d.ts +1 -1
  17. package/dist/runtime/nitro/utils/awaitPatterns/time.js +6 -2
  18. package/dist/runtime/nitro/utils/awaitPatterns/webhook.js +53 -45
  19. package/dist/runtime/nitro/utils/defineFunction.d.ts +2 -9
  20. package/dist/runtime/nitro/utils/defineFunction.js +1 -14
  21. package/dist/runtime/nitro/utils/defineFunctionConfig.d.ts +84 -16
  22. package/dist/runtime/nitro/utils/defineHooks.d.ts +64 -10
  23. package/dist/runtime/nitro/utils/defineHooks.js +3 -0
  24. package/dist/runtime/nitro/utils/useAwait.d.ts +12 -0
  25. package/dist/runtime/nitro/utils/useAwait.js +34 -4
  26. package/dist/runtime/nitro/utils/useFlow.js +13 -2
  27. package/dist/runtime/nitro/utils/useHookRegistry.d.ts +10 -4
  28. package/dist/runtime/scheduler/scheduler.d.ts +19 -0
  29. package/dist/runtime/scheduler/scheduler.js +184 -8
  30. package/dist/runtime/scheduler/types.d.ts +6 -0
  31. package/dist/runtime/worker/node/runner.js +32 -91
  32. package/dist/runtime/worker/system/awaitHandlers.d.ts +27 -0
  33. package/dist/runtime/worker/system/awaitHandlers.js +230 -0
  34. package/dist/runtime/worker/system/index.d.ts +24 -0
  35. package/dist/runtime/worker/system/index.js +39 -0
  36. package/package.json +1 -1
@@ -1,24 +1,19 @@
1
- import { useNventLogger, useStreamTopics, $useAnalyzedFlows, useScheduler } from "#imports";
2
- const DEFAULT_STALL_TIMEOUT = 30 * 60 * 1e3;
3
- const DEFAULT_CHECK_INTERVAL = 15 * 60 * 1e3;
1
+ import { useNventLogger, useStreamTopics, $useAnalyzedFlows } from "#imports";
4
2
  export class FlowStallDetector {
5
3
  store;
6
4
  config;
7
5
  logger = useNventLogger("stall-detector");
8
- schedulerJobId;
9
6
  started = false;
10
7
  constructor(store, config = {}) {
11
8
  this.store = store;
12
9
  this.config = {
13
- stallTimeout: config.stallTimeout ?? DEFAULT_STALL_TIMEOUT,
14
- checkInterval: config.checkInterval ?? DEFAULT_CHECK_INTERVAL,
15
- enablePeriodicCheck: config.enablePeriodicCheck ?? true
10
+ enabled: config.enabled ?? true
16
11
  };
17
12
  }
18
13
  /**
19
- * Start the periodic stall detector
20
- * Should be called once per instance after adapters are initialized
14
+ * Start the stall detector
21
15
  * Runs startup recovery to clean up flows from previous server instances
16
+ * Note: Periodic checking removed - now uses per-flow scheduler jobs
22
17
  */
23
18
  async start() {
24
19
  if (this.started) {
@@ -27,108 +22,14 @@ export class FlowStallDetector {
27
22
  }
28
23
  this.started = true;
29
24
  await this.runStartupRecovery();
30
- this.logger.info(`Stall detector started - periodicCheck: ${this.config.enablePeriodicCheck}, stallTimeout: ${this.config.stallTimeout / 1e3}s, checkInterval: ${this.config.checkInterval / 1e3}s`);
25
+ this.logger.info("Stall detector started - using per-flow scheduler jobs for stall timeouts");
31
26
  }
32
27
  /**
33
- * Get the configuration for scheduling
34
- * Returns config needed by flowWiring to register the scheduler job
35
- */
36
- getScheduleConfig() {
37
- return {
38
- enabled: this.config.enablePeriodicCheck,
39
- interval: this.config.checkInterval,
40
- stallTimeout: this.config.stallTimeout
41
- };
42
- }
43
- /**
44
- * Set the scheduler job ID (called from flowWiring after scheduling)
45
- */
46
- setSchedulerJobId(jobId) {
47
- this.schedulerJobId = jobId;
48
- }
49
- /**
50
- * Stop the periodic stall detector
28
+ * Stop the stall detector
51
29
  */
52
30
  async stop() {
53
- if (this.schedulerJobId) {
54
- try {
55
- const scheduler = useScheduler();
56
- await scheduler.unschedule(this.schedulerJobId);
57
- this.schedulerJobId = void 0;
58
- this.logger.info("Stopped periodic stall detector");
59
- } catch (error) {
60
- this.logger.error(`Failed to stop stall detector: ${error.message}`);
61
- }
62
- }
63
31
  this.started = false;
64
- }
65
- /**
66
- * Get stall timeout for a specific flow
67
- * Uses flow-specific timeout from analyzed metadata, falls back to global config
68
- */
69
- async getFlowStallTimeout(flowName) {
70
- try {
71
- const analyzedFlows = $useAnalyzedFlows();
72
- const flowMeta = analyzedFlows.find((f) => f.id === flowName);
73
- if (flowMeta?.stallTimeout) {
74
- this.logger.debug(`Using flow-specific stall timeout for '${flowName}': ${flowMeta.stallTimeout / 1e3}s`);
75
- return flowMeta.stallTimeout;
76
- }
77
- } catch (error) {
78
- this.logger.warn(`Failed to get flow-specific stall timeout for '${flowName}': ${error.message}`);
79
- }
80
- return this.config.stallTimeout;
81
- }
82
- /**
83
- * Update activity timestamp for a flow
84
- * Should be called on every step event (started, completed, failed, retry)
85
- */
86
- async updateActivity(flowName, runId) {
87
- const { StoreSubjects } = useStreamTopics();
88
- const indexKey = StoreSubjects.flowRunIndex(flowName);
89
- try {
90
- if (!this.store.index.update) {
91
- this.logger.warn("Store does not support indexUpdate, cannot update activity");
92
- return;
93
- }
94
- await this.store.index.update(indexKey, runId, {
95
- lastActivityAt: Date.now()
96
- });
97
- } catch (error) {
98
- this.logger.warn(`Failed to update flow activity for '${flowName}' runId '${runId}': ${error.message}`);
99
- }
100
- }
101
- /**
102
- * Check if a specific flow is stalled (lazy detection)
103
- * Returns true if the flow should be marked as stalled
104
- * v0.5: Await-aware - uses flow-specific timeout and skips awaiting flows
105
- */
106
- async isStalled(flowName, runId) {
107
- const { StoreSubjects } = useStreamTopics();
108
- const indexKey = StoreSubjects.flowRunIndex(flowName);
109
- try {
110
- if (!this.store.index.get) return false;
111
- const flowEntry = await this.store.index.get(indexKey, runId);
112
- if (!flowEntry?.metadata) return false;
113
- if (flowEntry.metadata.status !== "running") return false;
114
- const awaitingSteps = flowEntry.metadata.awaitingSteps || {};
115
- const hasActiveAwaits = Object.keys(awaitingSteps).length > 0;
116
- if (hasActiveAwaits) {
117
- this.logger.debug(`Flow '${flowName}' runId '${runId}' has active awaits [${Object.keys(awaitingSteps).join(", ")}], skipping stall check`);
118
- return false;
119
- }
120
- const stallTimeout = await this.getFlowStallTimeout(flowName);
121
- const lastActivity = flowEntry.metadata.lastActivityAt || flowEntry.metadata.startedAt || 0;
122
- const timeSinceActivity = Date.now() - lastActivity;
123
- if (timeSinceActivity > stallTimeout) {
124
- this.logger.info(`Flow detected as stalled (lazy check) - '${flowName}' runId '${runId}': ${Math.round(timeSinceActivity / 1e3)}s since activity (timeout: ${stallTimeout / 1e3}s)`);
125
- return true;
126
- }
127
- return false;
128
- } catch (error) {
129
- this.logger.warn(`Failed to check if flow is stalled for '${flowName}' runId '${runId}': ${error.message}`);
130
- return false;
131
- }
32
+ this.logger.info("Stall detector stopped");
132
33
  }
133
34
  /**
134
35
  * Mark a flow as stalled
@@ -171,72 +72,6 @@ export class FlowStallDetector {
171
72
  this.logger.error(`Failed to mark flow as stalled for '${flowName}' runId '${runId}': ${error.message}`);
172
73
  }
173
74
  }
174
- /**
175
- * Check all running flows and mark stalled ones
176
- * This is called by the periodic background job
177
- *
178
- * Note: This method requires knowledge of which flows exist.
179
- * For now, we'll need to pass flow names to check, or iterate known flows from registry.
180
- */
181
- async checkFlowsForStalls(flowNames) {
182
- this.logger.info(`Running periodic stall check for ${flowNames.length} flows`);
183
- try {
184
- if (!this.store.index.get || !this.store.index.read) {
185
- this.logger.warn("Store does not support required index operations");
186
- return;
187
- }
188
- const { StoreSubjects } = useStreamTopics();
189
- let checkedCount = 0;
190
- let stalledCount = 0;
191
- for (const flowName of flowNames) {
192
- const indexKey = StoreSubjects.flowRunIndex(flowName);
193
- const flowStallTimeout = await this.getFlowStallTimeout(flowName);
194
- const entries = await this.store.index.read(indexKey, { limit: 1e3 });
195
- for (const entry of entries) {
196
- if (!entry.metadata) continue;
197
- checkedCount++;
198
- if (entry.metadata.status !== "running" && entry.metadata.status !== "awaiting") continue;
199
- const awaitingSteps = entry.metadata.awaitingSteps || {};
200
- const awaitingStepNames = Object.keys(awaitingSteps);
201
- if (awaitingStepNames.length > 0) {
202
- let hasOverdueAwaits = false;
203
- let hasLegacyAwait = false;
204
- for (const stepName of awaitingStepNames) {
205
- const awaitState = awaitingSteps[stepName];
206
- if (awaitState?.status === "awaiting") {
207
- if (!awaitState.timeoutAt) {
208
- hasLegacyAwait = true;
209
- } else if (Date.now() > awaitState.timeoutAt) {
210
- hasOverdueAwaits = true;
211
- break;
212
- }
213
- }
214
- }
215
- if (hasOverdueAwaits) {
216
- await this.markAsStalled(flowName, entry.id, "Await pattern timed out");
217
- stalledCount++;
218
- continue;
219
- }
220
- if (hasLegacyAwait) {
221
- this.logger.debug(`Skipping flow with legacy await (no timeout) - '${flowName}' runId '${entry.id}'`);
222
- }
223
- continue;
224
- }
225
- const lastActivity = entry.metadata.lastActivityAt || entry.metadata.startedAt || 0;
226
- const timeSinceActivity = Date.now() - lastActivity;
227
- if (timeSinceActivity > flowStallTimeout) {
228
- await this.markAsStalled(flowName, entry.id, "Periodic check detected no activity");
229
- stalledCount++;
230
- }
231
- }
232
- }
233
- this.logger.info(`Periodic stall check completed - checked: ${checkedCount}, stalled: ${stalledCount}`);
234
- } catch (error) {
235
- this.logger.error("Failed to run periodic stall check", {
236
- error: error.message
237
- });
238
- }
239
- }
240
75
  /**
241
76
  * Run startup recovery to clean up flows left in running state from previous server instance
242
77
  * This marks all running flows as stalled since their in-memory state is lost
@@ -402,32 +237,13 @@ export class FlowStallDetector {
402
237
  this.logger.error(`Failed to validate flow stats: ${error.message}`);
403
238
  }
404
239
  }
405
- /**
406
- * Internal method for periodic checks
407
- * Gets flow names from registry and checks them
408
- */
409
- async checkAllRunningFlows() {
410
- try {
411
- const analyzedFlows = $useAnalyzedFlows();
412
- const flowNames = analyzedFlows.map((f) => f.id).filter(Boolean);
413
- if (flowNames.length === 0) {
414
- this.logger.debug("No flows registered, skipping stall check");
415
- return;
416
- }
417
- await this.checkFlowsForStalls(flowNames);
418
- } catch (error) {
419
- this.logger.error(`Failed to run periodic stall check: ${error.message}`);
420
- }
421
- }
422
240
  /**
423
241
  * Get stall detector statistics
424
242
  */
425
243
  getStats() {
426
244
  return {
427
245
  enabled: this.started,
428
- periodicCheckEnabled: this.config.enablePeriodicCheck,
429
- stallTimeout: this.config.stallTimeout,
430
- checkInterval: this.config.checkInterval
246
+ mode: "per-flow-scheduler"
431
247
  };
432
248
  }
433
249
  }