@blokjs/runner 0.4.0 → 0.6.0

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 (163) hide show
  1. package/dist/Blok.js +32 -3
  2. package/dist/Blok.js.map +1 -1
  3. package/dist/Configuration.d.ts +41 -5
  4. package/dist/Configuration.js +215 -92
  5. package/dist/Configuration.js.map +1 -1
  6. package/dist/ForEachNode.d.ts +59 -0
  7. package/dist/ForEachNode.js +522 -0
  8. package/dist/ForEachNode.js.map +1 -0
  9. package/dist/LoopMaxIterationsError.d.ts +11 -0
  10. package/dist/LoopMaxIterationsError.js +18 -0
  11. package/dist/LoopMaxIterationsError.js.map +1 -0
  12. package/dist/LoopNode.d.ts +36 -0
  13. package/dist/LoopNode.js +182 -0
  14. package/dist/LoopNode.js.map +1 -0
  15. package/dist/Runner.d.ts +11 -1
  16. package/dist/Runner.js +9 -2
  17. package/dist/Runner.js.map +1 -1
  18. package/dist/RunnerSteps.js +419 -112
  19. package/dist/RunnerSteps.js.map +1 -1
  20. package/dist/RuntimeAdapterNode.d.ts +2 -1
  21. package/dist/RuntimeAdapterNode.js +2 -2
  22. package/dist/RuntimeAdapterNode.js.map +1 -1
  23. package/dist/RuntimeRegistry.d.ts +23 -2
  24. package/dist/RuntimeRegistry.js +31 -2
  25. package/dist/RuntimeRegistry.js.map +1 -1
  26. package/dist/SubworkflowNode.d.ts +106 -0
  27. package/dist/SubworkflowNode.js +261 -3
  28. package/dist/SubworkflowNode.js.map +1 -1
  29. package/dist/SwitchNode.d.ts +37 -0
  30. package/dist/SwitchNode.js +153 -0
  31. package/dist/SwitchNode.js.map +1 -0
  32. package/dist/TriggerBase.d.ts +50 -0
  33. package/dist/TriggerBase.js +262 -4
  34. package/dist/TriggerBase.js.map +1 -1
  35. package/dist/TryCatchNode.d.ts +32 -0
  36. package/dist/TryCatchNode.js +207 -0
  37. package/dist/TryCatchNode.js.map +1 -0
  38. package/dist/adapters/grpc/GrpcCodec.js +2 -2
  39. package/dist/adapters/grpc/GrpcRuntimeAdapter.d.ts +6 -4
  40. package/dist/adapters/grpc/GrpcRuntimeAdapter.js +6 -4
  41. package/dist/adapters/grpc/GrpcRuntimeAdapter.js.map +1 -1
  42. package/dist/adapters/grpc/types.d.ts +7 -5
  43. package/dist/adapters/grpc/types.js.map +1 -1
  44. package/dist/adapters/transport.d.ts +12 -41
  45. package/dist/adapters/transport.js +21 -70
  46. package/dist/adapters/transport.js.map +1 -1
  47. package/dist/cache/NodeResultCache.js +7 -0
  48. package/dist/cache/NodeResultCache.js.map +1 -1
  49. package/dist/concurrency/NatsKvConcurrencyBackend.js +18 -5
  50. package/dist/concurrency/NatsKvConcurrencyBackend.js.map +1 -1
  51. package/dist/concurrency/RedisConcurrencyBackend.d.ts +64 -0
  52. package/dist/concurrency/RedisConcurrencyBackend.js +374 -0
  53. package/dist/concurrency/RedisConcurrencyBackend.js.map +1 -0
  54. package/dist/concurrency/createConcurrencyBackend.d.ts +1 -0
  55. package/dist/concurrency/createConcurrencyBackend.js +5 -1
  56. package/dist/concurrency/createConcurrencyBackend.js.map +1 -1
  57. package/dist/defineNode.d.ts +8 -0
  58. package/dist/defineNode.js +25 -5
  59. package/dist/defineNode.js.map +1 -1
  60. package/dist/graphql/GraphQLSchemaGenerator.js +1 -1
  61. package/dist/graphql/GraphQLSchemaGenerator.js.map +1 -1
  62. package/dist/index.d.ts +10 -6
  63. package/dist/index.js +13 -9
  64. package/dist/index.js.map +1 -1
  65. package/dist/marketplace/RuntimeCatalog.d.ts +6 -0
  66. package/dist/marketplace/RuntimeCatalog.js.map +1 -1
  67. package/dist/marketplace/RuntimeDiscovery.d.ts +2 -2
  68. package/dist/marketplace/RuntimeDiscovery.js +18 -6
  69. package/dist/marketplace/RuntimeDiscovery.js.map +1 -1
  70. package/dist/monitoring/ConcurrencyMetrics.d.ts +26 -0
  71. package/dist/monitoring/ConcurrencyMetrics.js +36 -4
  72. package/dist/monitoring/ConcurrencyMetrics.js.map +1 -1
  73. package/dist/monitoring/ForEachWaitMetrics.d.ts +22 -0
  74. package/dist/monitoring/ForEachWaitMetrics.js +36 -0
  75. package/dist/monitoring/ForEachWaitMetrics.js.map +1 -0
  76. package/dist/openapi/OpenAPIGenerator.js +7 -2
  77. package/dist/openapi/OpenAPIGenerator.js.map +1 -1
  78. package/dist/runtime/PrimitiveStack.d.ts +64 -0
  79. package/dist/runtime/PrimitiveStack.js +92 -0
  80. package/dist/runtime/PrimitiveStack.js.map +1 -0
  81. package/dist/scheduling/DebounceBackend.d.ts +108 -0
  82. package/dist/scheduling/DebounceBackend.js +23 -0
  83. package/dist/scheduling/DebounceBackend.js.map +1 -0
  84. package/dist/scheduling/DebounceCoordinator.d.ts +65 -12
  85. package/dist/scheduling/DebounceCoordinator.js +234 -13
  86. package/dist/scheduling/DebounceCoordinator.js.map +1 -1
  87. package/dist/scheduling/DeferredRunScheduler.d.ts +28 -0
  88. package/dist/scheduling/DeferredRunScheduler.js +105 -3
  89. package/dist/scheduling/DeferredRunScheduler.js.map +1 -1
  90. package/dist/scheduling/NatsKvDebounceBackend.d.ts +53 -0
  91. package/dist/scheduling/NatsKvDebounceBackend.js +334 -0
  92. package/dist/scheduling/NatsKvDebounceBackend.js.map +1 -0
  93. package/dist/scheduling/RedisDebounceBackend.d.ts +49 -0
  94. package/dist/scheduling/RedisDebounceBackend.js +356 -0
  95. package/dist/scheduling/RedisDebounceBackend.js.map +1 -0
  96. package/dist/scheduling/createDebounceBackend.d.ts +25 -0
  97. package/dist/scheduling/createDebounceBackend.js +39 -0
  98. package/dist/scheduling/createDebounceBackend.js.map +1 -0
  99. package/dist/security/AuditLogger.js +1 -1
  100. package/dist/security/AuditLogger.js.map +1 -1
  101. package/dist/security/AuthMiddleware.d.ts +19 -20
  102. package/dist/security/AuthMiddleware.js +35 -20
  103. package/dist/security/AuthMiddleware.js.map +1 -1
  104. package/dist/security/OAuthProvider.js +2 -2
  105. package/dist/security/OAuthProvider.js.map +1 -1
  106. package/dist/security/SecretManager.js +14 -13
  107. package/dist/security/SecretManager.js.map +1 -1
  108. package/dist/security/index.d.ts +3 -1
  109. package/dist/security/index.js +3 -1
  110. package/dist/security/index.js.map +1 -1
  111. package/dist/testing/TestHarness.d.ts +27 -12
  112. package/dist/testing/TestHarness.js +19 -3
  113. package/dist/testing/TestHarness.js.map +1 -1
  114. package/dist/testing/WorkflowTestRunner.js +0 -7
  115. package/dist/testing/WorkflowTestRunner.js.map +1 -1
  116. package/dist/tracing/InMemoryRunStore.d.ts +14 -1
  117. package/dist/tracing/InMemoryRunStore.js +95 -6
  118. package/dist/tracing/InMemoryRunStore.js.map +1 -1
  119. package/dist/tracing/PostgresRunStore.d.ts +28 -2
  120. package/dist/tracing/PostgresRunStore.js +276 -3
  121. package/dist/tracing/PostgresRunStore.js.map +1 -1
  122. package/dist/tracing/RoutingDiagnostics.d.ts +55 -0
  123. package/dist/tracing/RoutingDiagnostics.js +50 -0
  124. package/dist/tracing/RoutingDiagnostics.js.map +1 -0
  125. package/dist/tracing/RunStore.d.ts +82 -1
  126. package/dist/tracing/RunTracker.d.ts +7 -1
  127. package/dist/tracing/RunTracker.js +23 -0
  128. package/dist/tracing/RunTracker.js.map +1 -1
  129. package/dist/tracing/SqliteRunStore.d.ts +57 -2
  130. package/dist/tracing/SqliteRunStore.js +408 -48
  131. package/dist/tracing/SqliteRunStore.js.map +1 -1
  132. package/dist/tracing/TraceRouter.js +380 -18
  133. package/dist/tracing/TraceRouter.js.map +1 -1
  134. package/dist/tracing/createStore.js +14 -3
  135. package/dist/tracing/createStore.js.map +1 -1
  136. package/dist/tracing/metadataFilter.d.ts +63 -0
  137. package/dist/tracing/metadataFilter.js +224 -0
  138. package/dist/tracing/metadataFilter.js.map +1 -0
  139. package/dist/tracing/types.d.ts +331 -7
  140. package/dist/utils/envAllowlist.d.ts +35 -0
  141. package/dist/utils/envAllowlist.js +113 -0
  142. package/dist/utils/envAllowlist.js.map +1 -0
  143. package/dist/version/RuntimeVersionValidator.d.ts +38 -0
  144. package/dist/version/RuntimeVersionValidator.js +121 -0
  145. package/dist/version/RuntimeVersionValidator.js.map +1 -0
  146. package/dist/visualization/WorkflowVisualizer.js +4 -4
  147. package/dist/visualization/WorkflowVisualizer.js.map +1 -1
  148. package/dist/workflow/PersistenceHelper.d.ts +18 -10
  149. package/dist/workflow/PersistenceHelper.js +35 -9
  150. package/dist/workflow/PersistenceHelper.js.map +1 -1
  151. package/dist/workflow/WorkflowNormalizer.d.ts +19 -1
  152. package/dist/workflow/WorkflowNormalizer.js +469 -19
  153. package/dist/workflow/WorkflowNormalizer.js.map +1 -1
  154. package/dist/workflow/WorkflowRegistry.d.ts +122 -0
  155. package/dist/workflow/WorkflowRegistry.js +121 -0
  156. package/dist/workflow/WorkflowRegistry.js.map +1 -1
  157. package/dist/workflow/sampleBody.d.ts +54 -0
  158. package/dist/workflow/sampleBody.js +320 -0
  159. package/dist/workflow/sampleBody.js.map +1 -0
  160. package/package.json +3 -8
  161. package/dist/adapters/HttpRuntimeAdapter.d.ts +0 -79
  162. package/dist/adapters/HttpRuntimeAdapter.js +0 -233
  163. package/dist/adapters/HttpRuntimeAdapter.js.map +0 -1
@@ -1,6 +1,40 @@
1
+ /**
2
+ * Tier 2 #7 — debounce coordinator. Tier C #1 — cross-process awareness.
3
+ *
4
+ * Coalesces rapid same-key triggers into a single delayed run. Modes:
5
+ *
6
+ * - `"trailing"` (default): each ping resets a timer; the run fires
7
+ * after `delayMs` of silence. Latest payload wins (within a single
8
+ * owning process). `maxDelayMs` bounds tail latency — even with
9
+ * continuous pings, the run fires after `maxDelayMs` from the FIRST
10
+ * ping.
11
+ * - `"leading"`: the first ping fires immediately. Subsequent pings
12
+ * within `delayMs` are dropped. Window resets after `delayMs` of
13
+ * silence.
14
+ *
15
+ * Process-wide singleton. **Default**: in-memory only — fast,
16
+ * synchronous internally. **Cross-process mode (Tier C #1)**: install a
17
+ * `DebounceBackend` via `setBackend()` and the coordinator routes
18
+ * register/cancel through the backend with the same outcome surface,
19
+ * keeping a local timer + closure for the OWNING process. The
20
+ * `register()` API is async — callers must `await` it.
21
+ *
22
+ * Latest-payload semantics in cross-process mode: **owner-local**.
23
+ * Pings from a non-owning process bump pingCount + push scheduledAt in
24
+ * the shared doc but do NOT contribute their payload — only the
25
+ * owning process's captured `onFire` closure fires. Cross-process
26
+ * latest-payload-wins is deferred (would require persisting each
27
+ * ping's payload to the shared doc; tracked in BACKLOG).
28
+ */
29
+ import { randomUUID } from "node:crypto";
30
+ const DEFAULT_OWNER_LEASE_MS = 60_000;
1
31
  export class DebounceCoordinator {
2
32
  static instance = null;
3
33
  states = new Map();
34
+ backend = null;
35
+ /** Process identity for cross-process owner-lease attribution. Stable for the lifetime of the singleton. */
36
+ processId = randomUUID();
37
+ ownerLeaseMs = DEFAULT_OWNER_LEASE_MS;
4
38
  static getInstance() {
5
39
  if (!DebounceCoordinator.instance) {
6
40
  DebounceCoordinator.instance = new DebounceCoordinator();
@@ -12,10 +46,41 @@ export class DebounceCoordinator {
12
46
  DebounceCoordinator.instance?.clear();
13
47
  DebounceCoordinator.instance = null;
14
48
  }
49
+ /**
50
+ * Install a cross-process backend. Set via `HttpTrigger.listen()` /
51
+ * `WorkerTrigger.listen()` when `BLOK_DEBOUNCE_BACKEND` is configured.
52
+ * Pass `null` to revert to the in-memory fast path.
53
+ */
54
+ setBackend(backend) {
55
+ this.backend = backend;
56
+ }
57
+ getBackend() {
58
+ return this.backend;
59
+ }
60
+ /**
61
+ * Override the owner-lease duration. Used by `HttpTrigger.listen()` /
62
+ * `WorkerTrigger.listen()` to apply `BLOK_DEBOUNCE_OWNER_LEASE_MS`.
63
+ */
64
+ setOwnerLeaseMs(ms) {
65
+ if (Number.isFinite(ms) && ms > 0) {
66
+ this.ownerLeaseMs = ms;
67
+ }
68
+ }
15
69
  bucket(workflowName, debounceKey) {
16
70
  return `${workflowName}\x1f${debounceKey}`;
17
71
  }
18
- register(opts) {
72
+ async register(opts) {
73
+ if (this.backend) {
74
+ return this.registerCrossProcess(opts);
75
+ }
76
+ return this.registerLocal(opts);
77
+ }
78
+ /**
79
+ * In-memory fast path — preserved exactly from the v1 single-process
80
+ * implementation. Synchronous internally; the outer signature is
81
+ * async so callers don't need to discriminate.
82
+ */
83
+ registerLocal(opts) {
19
84
  const now = opts.__now ?? Date.now();
20
85
  const bucketKey = this.bucket(opts.workflowName, opts.debounceKey);
21
86
  const existing = this.states.get(bucketKey);
@@ -66,7 +131,7 @@ export class DebounceCoordinator {
66
131
  const naiveDeadline = now + opts.delayMs;
67
132
  const dispatchAt = existing.maxDelayDeadline !== undefined ? Math.min(naiveDeadline, existing.maxDelayDeadline) : naiveDeadline;
68
133
  const wait = Math.max(0, dispatchAt - now);
69
- existing.timer = setTimeout(() => this.fireTrailing(bucketKey), wait);
134
+ existing.timer = setTimeout(() => this.fireTrailingLocal(bucketKey), wait);
70
135
  return {
71
136
  outcome: "coalesce",
72
137
  activeRunId: existing.activeRunId,
@@ -90,7 +155,7 @@ export class DebounceCoordinator {
90
155
  const naiveDeadline = now + opts.delayMs;
91
156
  const dispatchAt = state.maxDelayDeadline !== undefined ? Math.min(naiveDeadline, state.maxDelayDeadline) : naiveDeadline;
92
157
  const wait = Math.max(0, dispatchAt - now);
93
- state.timer = setTimeout(() => this.fireTrailing(bucketKey), wait);
158
+ state.timer = setTimeout(() => this.fireTrailingLocal(bucketKey), wait);
94
159
  this.states.set(bucketKey, state);
95
160
  return {
96
161
  outcome: "schedule-trailing",
@@ -99,7 +164,7 @@ export class DebounceCoordinator {
99
164
  pingCount: 1,
100
165
  };
101
166
  }
102
- fireTrailing(bucketKey) {
167
+ fireTrailingLocal(bucketKey) {
103
168
  const state = this.states.get(bucketKey);
104
169
  if (!state)
105
170
  return;
@@ -110,26 +175,182 @@ export class DebounceCoordinator {
110
175
  });
111
176
  }
112
177
  }
178
+ /**
179
+ * Cross-process path — delegates ownership to the backend and uses
180
+ * a local timer + closure for the OWNING process.
181
+ *
182
+ * Three outcomes from the backend:
183
+ * - `owner-new`: this process is the new owner. Start a local timer
184
+ * + closure; on fire, atomically finalize via the backend.
185
+ * - `owner-extend`: this process is already the owner. Cancel +
186
+ * restart the local timer at the new scheduledAt; refresh closure.
187
+ * - `coalesce`: another process owns the window. Just return.
188
+ *
189
+ * Leading mode: `owner-new` translates to `fire-immediate` (caller
190
+ * fires synchronously); `owner-extend`/`coalesce` translate to
191
+ * `coalesce`.
192
+ */
193
+ async registerCrossProcess(opts) {
194
+ const backend = this.backend;
195
+ if (!backend)
196
+ return this.registerLocal(opts);
197
+ const now = opts.__now ?? Date.now();
198
+ const bucketKey = this.bucket(opts.workflowName, opts.debounceKey);
199
+ let res;
200
+ try {
201
+ res = await backend.registerPing({
202
+ workflowName: opts.workflowName,
203
+ debounceKey: opts.debounceKey,
204
+ mode: opts.mode,
205
+ delayMs: opts.delayMs,
206
+ maxDelayMs: opts.maxDelayMs,
207
+ runId: opts.runId,
208
+ processId: this.processId,
209
+ ownerLeaseMs: this.ownerLeaseMs,
210
+ now,
211
+ });
212
+ }
213
+ catch (err) {
214
+ // Fail-open — fall back to local in-memory window. Same posture
215
+ // as the concurrency-backend fail-fast path (deny-on-error) but
216
+ // debounce isn't a safety gate — better to admit the ping than
217
+ // drop it on a transient broker outage.
218
+ console.warn(`[blok][scheduling] debounce backend registerPing failed for ${bucketKey}: ${err instanceof Error ? err.message : String(err)}; falling back to in-memory window`);
219
+ return this.registerLocal(opts);
220
+ }
221
+ // === Leading mode ===
222
+ if (opts.mode === "leading") {
223
+ if (res.outcome === "owner-new") {
224
+ // Caller fires synchronously; we don't keep a local timer for
225
+ // leading mode (the backend's owner-lease IS the window).
226
+ return { outcome: "fire-immediate", activeRunId: opts.runId, pingCount: res.pingCount };
227
+ }
228
+ return { outcome: "coalesce", activeRunId: res.activeRunId, pingCount: res.pingCount };
229
+ }
230
+ // === Trailing mode ===
231
+ if (res.outcome === "owner-new") {
232
+ // New trailing window owned by this process. Capture the closure +
233
+ // start a local timer to fire at backend-decided scheduledAt.
234
+ this.installOwnerTimer(bucketKey, opts, res.scheduledAt, now);
235
+ return {
236
+ outcome: "schedule-trailing",
237
+ activeRunId: opts.runId,
238
+ scheduledAt: res.scheduledAt,
239
+ pingCount: res.pingCount,
240
+ };
241
+ }
242
+ if (res.outcome === "owner-extend") {
243
+ // We still own. Replace the captured closure (latest payload
244
+ // wins within this process) + reschedule.
245
+ this.installOwnerTimer(bucketKey, opts, res.scheduledAt, now);
246
+ return {
247
+ outcome: "coalesce",
248
+ activeRunId: res.activeRunId,
249
+ scheduledAt: res.scheduledAt,
250
+ pingCount: res.pingCount,
251
+ };
252
+ }
253
+ // outcome === "coalesce" — another process owns. Do not install a
254
+ // local timer; the owning process drives the fire.
255
+ return {
256
+ outcome: "coalesce",
257
+ activeRunId: res.activeRunId,
258
+ scheduledAt: res.scheduledAt,
259
+ pingCount: res.pingCount,
260
+ };
261
+ }
262
+ installOwnerTimer(bucketKey, opts, scheduledAt, now) {
263
+ const existing = this.states.get(bucketKey);
264
+ if (existing?.timer)
265
+ clearTimeout(existing.timer);
266
+ const state = {
267
+ bucketKey,
268
+ mode: opts.mode,
269
+ delayMs: opts.delayMs,
270
+ maxDelayMs: opts.maxDelayMs,
271
+ firstPingAt: existing?.firstPingAt ?? now,
272
+ lastPingAt: now,
273
+ pingCount: (existing?.pingCount ?? 0) + 1,
274
+ activeRunId: opts.runId,
275
+ maxDelayDeadline: existing?.maxDelayDeadline ?? (opts.maxDelayMs !== undefined ? now + opts.maxDelayMs : undefined),
276
+ onFire: opts.onFire,
277
+ };
278
+ const wait = Math.max(0, scheduledAt - now);
279
+ state.timer = setTimeout(() => {
280
+ void this.fireTrailingCrossProcess(bucketKey, opts.workflowName, opts.debounceKey, opts.runId);
281
+ }, wait);
282
+ this.states.set(bucketKey, state);
283
+ }
284
+ async fireTrailingCrossProcess(bucketKey, workflowName, debounceKey, runId) {
285
+ const backend = this.backend;
286
+ const state = this.states.get(bucketKey);
287
+ if (!backend || !state)
288
+ return;
289
+ const now = Date.now();
290
+ let result;
291
+ try {
292
+ result = await backend.finalize(workflowName, debounceKey, runId, now);
293
+ }
294
+ catch (err) {
295
+ // Treat as abandoned — owner-lease will eventually expire and
296
+ // another process can take over. Don't fire to avoid duplicate
297
+ // dispatch.
298
+ console.warn(`[blok][scheduling] debounce backend finalize failed for ${bucketKey}: ${err instanceof Error ? err.message : String(err)}; abandoning local owner state`);
299
+ this.states.delete(bucketKey);
300
+ return;
301
+ }
302
+ if (result.finalize === "fire") {
303
+ this.states.delete(bucketKey);
304
+ if (state.onFire) {
305
+ void state.onFire().catch((err) => {
306
+ console.error(`[blok][scheduling] DebounceCoordinator cross-process fire failed for key ${bucketKey}:`, err instanceof Error ? err.stack || err.message : err);
307
+ });
308
+ }
309
+ return;
310
+ }
311
+ if (result.finalize === "reschedule") {
312
+ // Coalesce pings from other processes pushed scheduledAt forward.
313
+ // Reschedule local timer; closure stays.
314
+ if (state.timer)
315
+ clearTimeout(state.timer);
316
+ const wait = Math.max(0, result.scheduledAt - now);
317
+ state.timer = setTimeout(() => {
318
+ void this.fireTrailingCrossProcess(bucketKey, workflowName, debounceKey, runId);
319
+ }, wait);
320
+ return;
321
+ }
322
+ // finalize === "abandoned" — lease expired; another process took
323
+ // over. Drop the closure silently.
324
+ this.states.delete(bucketKey);
325
+ }
113
326
  /** Cancel an active window without firing. Returns true if cancelled. */
114
- cancel(workflowName, debounceKey) {
327
+ async cancel(workflowName, debounceKey) {
115
328
  const bucketKey = this.bucket(workflowName, debounceKey);
116
329
  const state = this.states.get(bucketKey);
117
- if (!state)
118
- return false;
119
- if (state.timer)
330
+ if (state?.timer)
120
331
  clearTimeout(state.timer);
121
- this.states.delete(bucketKey);
122
- return true;
332
+ const hadLocal = this.states.delete(bucketKey);
333
+ if (this.backend) {
334
+ try {
335
+ const cancelled = await this.backend.cancel(workflowName, debounceKey);
336
+ return cancelled || hadLocal;
337
+ }
338
+ catch (err) {
339
+ console.warn(`[blok][scheduling] debounce backend cancel failed for ${bucketKey}: ${err instanceof Error ? err.message : String(err)}`);
340
+ return hadLocal;
341
+ }
342
+ }
343
+ return hadLocal;
123
344
  }
124
- /** Number of active debounce windows. Tests + observability. */
345
+ /** Number of active LOCAL debounce windows. Tests + observability. Excludes cross-process windows owned by other processes. */
125
346
  size() {
126
347
  return this.states.size;
127
348
  }
128
- /** True if a window is open for `(workflow, key)`. */
349
+ /** True if THIS process has a local window for `(workflow, key)`. Excludes windows owned by other processes. */
129
350
  has(workflowName, debounceKey) {
130
351
  return this.states.has(this.bucket(workflowName, debounceKey));
131
352
  }
132
- /** Cancel everything without firing. */
353
+ /** Cancel everything without firing. Local state only — cross-process buckets fall back to lease-expiry. */
133
354
  clear() {
134
355
  for (const state of this.states.values()) {
135
356
  if (state.timer)
@@ -1 +1 @@
1
- {"version":3,"file":"DebounceCoordinator.js","sourceRoot":"","sources":["../../src/scheduling/DebounceCoordinator.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"DebounceCoordinator.js","sourceRoot":"","sources":["../../src/scheduling/DebounceCoordinator.ts"],"names":[],"mappings":"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"}
@@ -24,6 +24,18 @@ export interface DeferredScheduleOptions {
24
24
  export declare class DeferredRunScheduler {
25
25
  private static instance;
26
26
  private entries;
27
+ /**
28
+ * Tier C #2 — stable per-process identity used for claim ownership.
29
+ * Generated once per scheduler instance; surviving across resets is
30
+ * intentional (a "process restart" in production gets a fresh
31
+ * scheduler singleton and therefore a fresh processId — peers' stale
32
+ * claims expire after the lease).
33
+ */
34
+ private readonly processId;
35
+ /** Tier C #2 — running heartbeat timer; one per scheduler instance. */
36
+ private heartbeatTimer;
37
+ /** Tier C #2 — count of persisted entries currently registered. Heartbeat is only active when > 0. */
38
+ private persistedEntryCount;
27
39
  static getInstance(): DeferredRunScheduler;
28
40
  /** Test-only — reset the singleton. Cancels all pending timers. */
29
41
  static resetInstance(): void;
@@ -65,4 +77,20 @@ export declare class DeferredRunScheduler {
65
77
  drainAll(): Promise<void>;
66
78
  /** Cancel everything without dispatching. */
67
79
  clear(): void;
80
+ /**
81
+ * Stable per-process identity used for the claim API. Trigger boot
82
+ * recovery passes this to `RunStore.claimDispatches(processId, …)`
83
+ * so peers can recognize each other's claims.
84
+ */
85
+ getProcessId(): string;
86
+ private maybeStartHeartbeat;
87
+ private maybeStopHeartbeat;
88
+ private runHeartbeat;
68
89
  }
90
+ /**
91
+ * Public helper that returns the operator-configured claim-lease in
92
+ * ms. Used by `HttpTrigger.recoverDispatches()` to pass the lease to
93
+ * `RunStore.claimDispatches()`. Centralized so the env var name is
94
+ * defined in one place.
95
+ */
96
+ export declare function getSchedulerClaimLeaseMs(): number;
@@ -1,15 +1,32 @@
1
1
  /**
2
2
  * Tier 2 #5 — in-memory scheduler for deferred workflow runs. Tier 2
3
3
  * #5+#7 follow-up adds optional sqlite-backed durability via the
4
- * {@link DeferredScheduleOptions.persist} parameter.
4
+ * {@link DeferredScheduleOptions.persist} parameter. Tier C #2 adds
5
+ * cross-process claim heartbeats so multi-process deployments sharing
6
+ * a PG store don't double-fire the same dispatch.
5
7
  *
6
8
  * Process-wide singleton; obtained via {@link DeferredRunScheduler.getInstance}.
7
9
  * Reset between tests via {@link DeferredRunScheduler.resetInstance}.
8
10
  */
11
+ import { randomUUID } from "node:crypto";
9
12
  import { RunTracker } from "../tracing/RunTracker";
13
+ const DEFAULT_CLAIM_LEASE_MS = 60_000;
14
+ const DEFAULT_HEARTBEAT_INTERVAL_MS = 20_000;
10
15
  export class DeferredRunScheduler {
11
16
  static instance = null;
12
17
  entries = new Map();
18
+ /**
19
+ * Tier C #2 — stable per-process identity used for claim ownership.
20
+ * Generated once per scheduler instance; surviving across resets is
21
+ * intentional (a "process restart" in production gets a fresh
22
+ * scheduler singleton and therefore a fresh processId — peers' stale
23
+ * claims expire after the lease).
24
+ */
25
+ processId = randomUUID();
26
+ /** Tier C #2 — running heartbeat timer; one per scheduler instance. */
27
+ heartbeatTimer = null;
28
+ /** Tier C #2 — count of persisted entries currently registered. Heartbeat is only active when > 0. */
29
+ persistedEntryCount = 0;
13
30
  static getInstance() {
14
31
  if (!DeferredRunScheduler.instance) {
15
32
  DeferredRunScheduler.instance = new DeferredRunScheduler();
@@ -69,8 +86,11 @@ export class DeferredRunScheduler {
69
86
  this.entries.delete(runId);
70
87
  // Best-effort delete the persisted row before invoking dispatchFn —
71
88
  // dispatch will write the run's terminal status separately.
72
- if (persisted)
89
+ if (persisted) {
73
90
  this.deletePersistedRow(runId);
91
+ this.persistedEntryCount = Math.max(0, this.persistedEntryCount - 1);
92
+ this.maybeStopHeartbeat();
93
+ }
74
94
  void dispatchFn().catch((err) => {
75
95
  console.error(`[blok][scheduling] DeferredRunScheduler dispatch failed for run ${runId}:`, err instanceof Error ? err.stack || err.message : err);
76
96
  });
@@ -78,7 +98,20 @@ export class DeferredRunScheduler {
78
98
  // `Node` will keep the event loop alive for pending timers — that's
79
99
  // the desired behavior for delayed runs in long-running services.
80
100
  // `unref()` would be wrong here.
101
+ const wasPersisted = existing?.persisted === true;
81
102
  this.entries.set(runId, { runId, dispatchAt, timer, dispatchFn, persisted });
103
+ // Tier C #2 — track persisted entry count + manage heartbeat
104
+ // lifecycle. The heartbeat only runs while we have ≥1 persisted
105
+ // entry (otherwise there's nothing to keep claimed). Replace doesn't
106
+ // change the count.
107
+ if (persisted && !wasPersisted) {
108
+ this.persistedEntryCount++;
109
+ this.maybeStartHeartbeat();
110
+ }
111
+ else if (!persisted && wasPersisted) {
112
+ this.persistedEntryCount = Math.max(0, this.persistedEntryCount - 1);
113
+ this.maybeStopHeartbeat();
114
+ }
82
115
  }
83
116
  /**
84
117
  * Cancel a pending dispatch. Returns true if the entry existed and
@@ -99,8 +132,11 @@ export class DeferredRunScheduler {
99
132
  }
100
133
  clearTimeout(entry.timer);
101
134
  this.entries.delete(runId);
102
- if (entry.persisted)
135
+ if (entry.persisted) {
103
136
  this.deletePersistedRow(runId);
137
+ this.persistedEntryCount = Math.max(0, this.persistedEntryCount - 1);
138
+ this.maybeStopHeartbeat();
139
+ }
104
140
  return true;
105
141
  }
106
142
  deletePersistedRow(runId) {
@@ -149,6 +185,72 @@ export class DeferredRunScheduler {
149
185
  for (const entry of this.entries.values())
150
186
  clearTimeout(entry.timer);
151
187
  this.entries.clear();
188
+ this.persistedEntryCount = 0;
189
+ this.maybeStopHeartbeat();
152
190
  }
191
+ // === Tier C #2 — cross-process claim heartbeat ===
192
+ /**
193
+ * Stable per-process identity used for the claim API. Trigger boot
194
+ * recovery passes this to `RunStore.claimDispatches(processId, …)`
195
+ * so peers can recognize each other's claims.
196
+ */
197
+ getProcessId() {
198
+ return this.processId;
199
+ }
200
+ maybeStartHeartbeat() {
201
+ if (this.heartbeatTimer !== null)
202
+ return;
203
+ if (this.persistedEntryCount === 0)
204
+ return;
205
+ if (process.env.BLOK_SCHEDULER_CLAIM_DISABLED === "1")
206
+ return;
207
+ const intervalMs = readEnvInt("BLOK_SCHEDULER_HEARTBEAT_INTERVAL_MS", DEFAULT_HEARTBEAT_INTERVAL_MS);
208
+ this.heartbeatTimer = setInterval(() => {
209
+ this.runHeartbeat();
210
+ }, intervalMs);
211
+ // Don't keep the event loop alive solely for the heartbeat —
212
+ // the persisted entries' timers already do that. `unref()`
213
+ // avoids blocking shutdown when no entries are pending.
214
+ this.heartbeatTimer.unref?.();
215
+ }
216
+ maybeStopHeartbeat() {
217
+ if (this.heartbeatTimer === null)
218
+ return;
219
+ if (this.persistedEntryCount > 0)
220
+ return;
221
+ clearInterval(this.heartbeatTimer);
222
+ this.heartbeatTimer = null;
223
+ }
224
+ runHeartbeat() {
225
+ const tracker = RunTracker.getInstance();
226
+ if (!tracker.active)
227
+ return;
228
+ try {
229
+ tracker.getStore().heartbeatClaims(this.processId, Date.now());
230
+ }
231
+ catch (err) {
232
+ // Heartbeat failures are non-fatal — the lease will expire if
233
+ // they continue, and a peer will take over. Log + continue.
234
+ console.warn(`[blok][scheduling] heartbeatClaims failed: ${err instanceof Error ? err.message : String(err)}`);
235
+ }
236
+ }
237
+ }
238
+ function readEnvInt(name, fallback) {
239
+ const raw = process.env[name];
240
+ if (raw && /^\d+$/.test(raw)) {
241
+ const n = Number(raw);
242
+ if (Number.isFinite(n) && n > 0)
243
+ return n;
244
+ }
245
+ return fallback;
246
+ }
247
+ /**
248
+ * Public helper that returns the operator-configured claim-lease in
249
+ * ms. Used by `HttpTrigger.recoverDispatches()` to pass the lease to
250
+ * `RunStore.claimDispatches()`. Centralized so the env var name is
251
+ * defined in one place.
252
+ */
253
+ export function getSchedulerClaimLeaseMs() {
254
+ return readEnvInt("BLOK_SCHEDULER_CLAIM_LEASE_MS", DEFAULT_CLAIM_LEASE_MS);
153
255
  }
154
256
  //# sourceMappingURL=DeferredRunScheduler.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"DeferredRunScheduler.js","sourceRoot":"","sources":["../../src/scheduling/DeferredRunScheduler.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"DeferredRunScheduler.js","sourceRoot":"","sources":["../../src/scheduling/DeferredRunScheduler.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Tier C #1 · NATS KV-backed debounce backend.
3
+ *
4
+ * Coordinates per-(workflow, debounceKey) window state across processes
5
+ * via a single NATS JetStream KV value per bucket with revision-based
6
+ * compare-and-swap (OCC). Mirrors the storage model of
7
+ * `NatsKvConcurrencyBackend` but with a different document shape (one
8
+ * window per bucket, not a leases array).
9
+ *
10
+ * Acquire / extend / coalesce: a bounded CAS loop (10 retries) that
11
+ * reads → decides ownership → atomically writes. On retry exhaustion,
12
+ * fall back to admitting the ping as a `coalesce` against the current
13
+ * owner — debounce is not a safety gate, so we'd rather over-coalesce
14
+ * than drop pings on a contention spike.
15
+ *
16
+ * Finalize: same OCC pattern. The owning process atomically reads the
17
+ * doc, confirms it still owns AND `now >= scheduledAt`, and atomically
18
+ * deletes. On lease handoff, the owner discovers it no longer owns and
19
+ * abandons silently.
20
+ *
21
+ * **Owner-local payload**: this backend tracks `pingCount`,
22
+ * `lastPingAt`, and `scheduledAt` only — not the payload. Cross-process
23
+ * latest-payload-wins is a deferred follow-up.
24
+ */
25
+ import type { DebounceBackend, DebounceFinalizeResult, DebounceRegisterBackendOpts, DebounceRegisterBackendResult } from "./DebounceBackend";
26
+ export interface NatsKvDebounceConfig {
27
+ servers: string[];
28
+ token?: string;
29
+ user?: string;
30
+ pass?: string;
31
+ bucketName: string;
32
+ }
33
+ export declare function readNatsKvDebounceConfigFromEnv(): NatsKvDebounceConfig;
34
+ export declare class NatsKvDebounceBackend implements DebounceBackend {
35
+ readonly name = "nats-kv";
36
+ private nc;
37
+ private kv;
38
+ private readonly config;
39
+ private connected;
40
+ constructor(config?: Partial<NatsKvDebounceConfig>);
41
+ connect(): Promise<void>;
42
+ disconnect(): Promise<void>;
43
+ private bucketKey;
44
+ private encodeSegment;
45
+ private requireKv;
46
+ private computeScheduledAt;
47
+ registerPing(opts: DebounceRegisterBackendOpts): Promise<DebounceRegisterBackendResult>;
48
+ finalize(workflowName: string, debounceKey: string, runId: string, now: number): Promise<DebounceFinalizeResult>;
49
+ cancel(workflowName: string, debounceKey: string): Promise<boolean>;
50
+ purgeExpired(now: number): Promise<number>;
51
+ private safeGet;
52
+ private parseDoc;
53
+ }