@blokjs/runner 0.6.21 → 0.7.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 (167) hide show
  1. package/dist/Blok.d.ts +2 -0
  2. package/dist/Blok.js +42 -110
  3. package/dist/Blok.js.map +1 -1
  4. package/dist/DefaultLogger.d.ts +13 -0
  5. package/dist/DefaultLogger.js +25 -0
  6. package/dist/DefaultLogger.js.map +1 -1
  7. package/dist/RunnerSteps.d.ts +23 -0
  8. package/dist/RunnerSteps.js +128 -87
  9. package/dist/RunnerSteps.js.map +1 -1
  10. package/dist/SubworkflowNode.js +19 -0
  11. package/dist/SubworkflowNode.js.map +1 -1
  12. package/dist/TriggerBase.d.ts +12 -0
  13. package/dist/TriggerBase.js +216 -181
  14. package/dist/TriggerBase.js.map +1 -1
  15. package/dist/adapters/grpc/GrpcRuntimeAdapter.d.ts +9 -0
  16. package/dist/adapters/grpc/GrpcRuntimeAdapter.js +76 -6
  17. package/dist/adapters/grpc/GrpcRuntimeAdapter.js.map +1 -1
  18. package/dist/index.d.ts +4 -39
  19. package/dist/index.js +7 -32
  20. package/dist/index.js.map +1 -1
  21. package/dist/monitoring/JanitorMetrics.d.ts +3 -0
  22. package/dist/monitoring/JanitorMetrics.js +11 -0
  23. package/dist/monitoring/JanitorMetrics.js.map +1 -1
  24. package/dist/monitoring/ProcessErrorMetrics.d.ts +32 -0
  25. package/dist/monitoring/ProcessErrorMetrics.js +43 -0
  26. package/dist/monitoring/ProcessErrorMetrics.js.map +1 -0
  27. package/dist/monitoring/PrometheusMetricsBridge.d.ts +7 -0
  28. package/dist/monitoring/PrometheusMetricsBridge.js +8 -2
  29. package/dist/monitoring/PrometheusMetricsBridge.js.map +1 -1
  30. package/dist/monitoring/SubworkflowMetrics.d.ts +25 -0
  31. package/dist/monitoring/SubworkflowMetrics.js +38 -0
  32. package/dist/monitoring/SubworkflowMetrics.js.map +1 -0
  33. package/dist/observability/ErrorSink.d.ts +23 -0
  34. package/dist/observability/ErrorSink.js +32 -0
  35. package/dist/observability/ErrorSink.js.map +1 -0
  36. package/dist/observability/SentryIntegration.d.ts +9 -0
  37. package/dist/observability/SentryIntegration.js +31 -0
  38. package/dist/observability/SentryIntegration.js.map +1 -0
  39. package/dist/scheduling/DebounceCoordinator.d.ts +7 -53
  40. package/dist/scheduling/DebounceCoordinator.js +8 -207
  41. package/dist/scheduling/DebounceCoordinator.js.map +1 -1
  42. package/dist/tracing/InMemoryRunStore.d.ts +5 -1
  43. package/dist/tracing/InMemoryRunStore.js +14 -0
  44. package/dist/tracing/InMemoryRunStore.js.map +1 -1
  45. package/dist/tracing/Janitor.js +3 -0
  46. package/dist/tracing/Janitor.js.map +1 -1
  47. package/dist/tracing/PostgresRunStore.d.ts +4 -1
  48. package/dist/tracing/PostgresRunStore.js +73 -3
  49. package/dist/tracing/PostgresRunStore.js.map +1 -1
  50. package/dist/tracing/RunStore.d.ts +17 -1
  51. package/dist/tracing/RunTracker.d.ts +13 -34
  52. package/dist/tracing/RunTracker.js +62 -32
  53. package/dist/tracing/RunTracker.js.map +1 -1
  54. package/dist/tracing/SqliteRunStore.d.ts +4 -1
  55. package/dist/tracing/SqliteRunStore.js +60 -0
  56. package/dist/tracing/SqliteRunStore.js.map +1 -1
  57. package/dist/tracing/TraceRouter.d.ts +13 -0
  58. package/dist/tracing/TraceRouter.js +43 -11
  59. package/dist/tracing/TraceRouter.js.map +1 -1
  60. package/dist/tracing/TracingLogger.js +22 -0
  61. package/dist/tracing/TracingLogger.js.map +1 -1
  62. package/dist/tracing/createStore.js +51 -22
  63. package/dist/tracing/createStore.js.map +1 -1
  64. package/dist/tracing/types.d.ts +22 -0
  65. package/dist/types/GlobalOptions.d.ts +5 -7
  66. package/dist/workflow/WorkflowNormalizer.js +63 -0
  67. package/dist/workflow/WorkflowNormalizer.js.map +1 -1
  68. package/package.json +7 -4
  69. package/dist/cache/NodeResultCache.d.ts +0 -286
  70. package/dist/cache/NodeResultCache.js +0 -506
  71. package/dist/cache/NodeResultCache.js.map +0 -1
  72. package/dist/cache/index.d.ts +0 -1
  73. package/dist/cache/index.js +0 -2
  74. package/dist/cache/index.js.map +0 -1
  75. package/dist/concurrency/ConcurrencyBackend.d.ts +0 -61
  76. package/dist/concurrency/ConcurrencyBackend.js +0 -20
  77. package/dist/concurrency/ConcurrencyBackend.js.map +0 -1
  78. package/dist/concurrency/NatsKvConcurrencyBackend.d.ts +0 -64
  79. package/dist/concurrency/NatsKvConcurrencyBackend.js +0 -310
  80. package/dist/concurrency/NatsKvConcurrencyBackend.js.map +0 -1
  81. package/dist/concurrency/RedisConcurrencyBackend.d.ts +0 -64
  82. package/dist/concurrency/RedisConcurrencyBackend.js +0 -374
  83. package/dist/concurrency/RedisConcurrencyBackend.js.map +0 -1
  84. package/dist/concurrency/createConcurrencyBackend.d.ts +0 -24
  85. package/dist/concurrency/createConcurrencyBackend.js +0 -38
  86. package/dist/concurrency/createConcurrencyBackend.js.map +0 -1
  87. package/dist/graphql/GraphQLSchemaGenerator.d.ts +0 -129
  88. package/dist/graphql/GraphQLSchemaGenerator.js +0 -425
  89. package/dist/graphql/GraphQLSchemaGenerator.js.map +0 -1
  90. package/dist/integrations/APMIntegration.d.ts +0 -141
  91. package/dist/integrations/APMIntegration.js +0 -212
  92. package/dist/integrations/APMIntegration.js.map +0 -1
  93. package/dist/integrations/AzureMonitorIntegration.d.ts +0 -118
  94. package/dist/integrations/AzureMonitorIntegration.js +0 -254
  95. package/dist/integrations/AzureMonitorIntegration.js.map +0 -1
  96. package/dist/integrations/CloudWatchIntegration.d.ts +0 -135
  97. package/dist/integrations/CloudWatchIntegration.js +0 -293
  98. package/dist/integrations/CloudWatchIntegration.js.map +0 -1
  99. package/dist/integrations/SentryIntegration.d.ts +0 -153
  100. package/dist/integrations/SentryIntegration.js +0 -200
  101. package/dist/integrations/SentryIntegration.js.map +0 -1
  102. package/dist/integrations/index.d.ts +0 -19
  103. package/dist/integrations/index.js +0 -16
  104. package/dist/integrations/index.js.map +0 -1
  105. package/dist/marketplace/RuntimeAutoScaler.d.ts +0 -148
  106. package/dist/marketplace/RuntimeAutoScaler.js +0 -366
  107. package/dist/marketplace/RuntimeAutoScaler.js.map +0 -1
  108. package/dist/marketplace/RuntimeCatalog.d.ts +0 -180
  109. package/dist/marketplace/RuntimeCatalog.js +0 -339
  110. package/dist/marketplace/RuntimeCatalog.js.map +0 -1
  111. package/dist/marketplace/RuntimeDiscovery.d.ts +0 -86
  112. package/dist/marketplace/RuntimeDiscovery.js +0 -231
  113. package/dist/marketplace/RuntimeDiscovery.js.map +0 -1
  114. package/dist/marketplace/RuntimeHealthMonitor.d.ts +0 -100
  115. package/dist/marketplace/RuntimeHealthMonitor.js +0 -241
  116. package/dist/marketplace/RuntimeHealthMonitor.js.map +0 -1
  117. package/dist/marketplace/RuntimeMetricsDashboard.d.ts +0 -113
  118. package/dist/marketplace/RuntimeMetricsDashboard.js +0 -293
  119. package/dist/marketplace/RuntimeMetricsDashboard.js.map +0 -1
  120. package/dist/openapi/OpenAPIGenerator.d.ts +0 -192
  121. package/dist/openapi/OpenAPIGenerator.js +0 -378
  122. package/dist/openapi/OpenAPIGenerator.js.map +0 -1
  123. package/dist/openapi/index.d.ts +0 -20
  124. package/dist/openapi/index.js +0 -20
  125. package/dist/openapi/index.js.map +0 -1
  126. package/dist/scheduling/DebounceBackend.d.ts +0 -108
  127. package/dist/scheduling/DebounceBackend.js +0 -23
  128. package/dist/scheduling/DebounceBackend.js.map +0 -1
  129. package/dist/scheduling/NatsKvDebounceBackend.d.ts +0 -53
  130. package/dist/scheduling/NatsKvDebounceBackend.js +0 -334
  131. package/dist/scheduling/NatsKvDebounceBackend.js.map +0 -1
  132. package/dist/scheduling/RedisDebounceBackend.d.ts +0 -49
  133. package/dist/scheduling/RedisDebounceBackend.js +0 -356
  134. package/dist/scheduling/RedisDebounceBackend.js.map +0 -1
  135. package/dist/scheduling/createDebounceBackend.d.ts +0 -25
  136. package/dist/scheduling/createDebounceBackend.js +0 -39
  137. package/dist/scheduling/createDebounceBackend.js.map +0 -1
  138. package/dist/security/ABAC.d.ts +0 -224
  139. package/dist/security/ABAC.js +0 -380
  140. package/dist/security/ABAC.js.map +0 -1
  141. package/dist/security/AuditLogger.d.ts +0 -242
  142. package/dist/security/AuditLogger.js +0 -317
  143. package/dist/security/AuditLogger.js.map +0 -1
  144. package/dist/security/AuthMiddleware.d.ts +0 -162
  145. package/dist/security/AuthMiddleware.js +0 -289
  146. package/dist/security/AuthMiddleware.js.map +0 -1
  147. package/dist/security/EncryptionAtRest.d.ts +0 -206
  148. package/dist/security/EncryptionAtRest.js +0 -236
  149. package/dist/security/EncryptionAtRest.js.map +0 -1
  150. package/dist/security/OAuthProvider.d.ts +0 -334
  151. package/dist/security/OAuthProvider.js +0 -719
  152. package/dist/security/OAuthProvider.js.map +0 -1
  153. package/dist/security/PIIDetector.d.ts +0 -233
  154. package/dist/security/PIIDetector.js +0 -354
  155. package/dist/security/PIIDetector.js.map +0 -1
  156. package/dist/security/RBAC.d.ts +0 -143
  157. package/dist/security/RBAC.js +0 -285
  158. package/dist/security/RBAC.js.map +0 -1
  159. package/dist/security/SecretManager.d.ts +0 -652
  160. package/dist/security/SecretManager.js +0 -1147
  161. package/dist/security/SecretManager.js.map +0 -1
  162. package/dist/security/TLSConfig.d.ts +0 -305
  163. package/dist/security/TLSConfig.js +0 -550
  164. package/dist/security/TLSConfig.js.map +0 -1
  165. package/dist/security/index.d.ts +0 -81
  166. package/dist/security/index.js +0 -82
  167. package/dist/security/index.js.map +0 -1
@@ -1,64 +0,0 @@
1
- /**
2
- * Tier 2 #6 follow-up · NATS KV-backed concurrency backend.
3
- *
4
- * Coordinates per-(workflow, concurrencyKey) lease state across processes
5
- * via a single NATS JetStream KV value per bucket using revision-based
6
- * compare-and-swap (OCC).
7
- *
8
- * Storage model: one KV key per `(workflowName, concurrencyKey)` pair.
9
- * Value is a JSON `{leases: [{runId, expiresAt}]}` document. Bounded
10
- * cardinality assumption — typical concurrency keys hold 1-50 active
11
- * leases (per-tenant rate limits). For higher cardinality, a per-lease
12
- * key model would scale better; revisit when needed.
13
- *
14
- * Atomicity: NATS KV's only guarantee is `kv.create(key, value)` (fails
15
- * on conflict) and `kv.update(key, value, expectedRevision)` (fails on
16
- * concurrent modification). The acquire loop reads → filters → checks
17
- * limit → CAS update. On CAS failure, retry up to 10 times then
18
- * fail-closed (deny the slot).
19
- *
20
- * Lease leak: each lease carries an `expiresAt`. Expired leases are
21
- * lazy-purged inside the same `acquireSlot` call that observes them;
22
- * an explicit `purgeExpired` sweep is also exposed for janitor use.
23
- */
24
- import type { ConcurrencySlotResult } from "../tracing/types";
25
- import type { ConcurrencyBackend } from "./ConcurrencyBackend";
26
- export interface NatsKvConcurrencyConfig {
27
- servers: string[];
28
- token?: string;
29
- user?: string;
30
- pass?: string;
31
- bucketName: string;
32
- }
33
- /**
34
- * Read configuration from environment variables. Used by
35
- * {@link createConcurrencyBackend} when the user opts into NATS KV.
36
- */
37
- export declare function readNatsKvConfigFromEnv(): NatsKvConcurrencyConfig;
38
- export declare class NatsKvConcurrencyBackend implements ConcurrencyBackend {
39
- readonly name = "nats-kv";
40
- private nc;
41
- private kv;
42
- private readonly config;
43
- private connected;
44
- constructor(config?: Partial<NatsKvConcurrencyConfig>);
45
- connect(): Promise<void>;
46
- disconnect(): Promise<void>;
47
- private bucketKey;
48
- private encodeSegment;
49
- private requireKv;
50
- acquireSlot(workflowName: string, concurrencyKey: string, concurrencyLimit: number, runId: string, leaseExpiresAt: number): Promise<ConcurrencySlotResult>;
51
- releaseSlot(workflowName: string, concurrencyKey: string, runId: string): Promise<void>;
52
- purgeExpired(now: number): Promise<number>;
53
- /**
54
- * PR 2 A6 — distinguishes legitimate "key not found" from "broker
55
- * unreachable / non-NotFound error". Returns:
56
- * - `NatsKvEntry` on a successful fetch.
57
- * - `null` when the key doesn't exist (NotFound code or null entry).
58
- * - `"fetch-failed"` for any other error (transient broker outage,
59
- * auth failure, network blip, etc.) so the OCC loop can fail-fast
60
- * instead of spinning 10× before fail-closing.
61
- */
62
- private safeGet;
63
- private parseBucket;
64
- }
@@ -1,310 +0,0 @@
1
- /**
2
- * Tier 2 #6 follow-up · NATS KV-backed concurrency backend.
3
- *
4
- * Coordinates per-(workflow, concurrencyKey) lease state across processes
5
- * via a single NATS JetStream KV value per bucket using revision-based
6
- * compare-and-swap (OCC).
7
- *
8
- * Storage model: one KV key per `(workflowName, concurrencyKey)` pair.
9
- * Value is a JSON `{leases: [{runId, expiresAt}]}` document. Bounded
10
- * cardinality assumption — typical concurrency keys hold 1-50 active
11
- * leases (per-tenant rate limits). For higher cardinality, a per-lease
12
- * key model would scale better; revisit when needed.
13
- *
14
- * Atomicity: NATS KV's only guarantee is `kv.create(key, value)` (fails
15
- * on conflict) and `kv.update(key, value, expectedRevision)` (fails on
16
- * concurrent modification). The acquire loop reads → filters → checks
17
- * limit → CAS update. On CAS failure, retry up to 10 times then
18
- * fail-closed (deny the slot).
19
- *
20
- * Lease leak: each lease carries an `expiresAt`. Expired leases are
21
- * lazy-purged inside the same `acquireSlot` call that observes them;
22
- * an explicit `purgeExpired` sweep is also exposed for janitor use.
23
- */
24
- import { ConcurrencyMetrics } from "../monitoring/ConcurrencyMetrics";
25
- const DEFAULT_BUCKET_NAME = "blok-concurrency";
26
- const MAX_CAS_RETRIES = 10;
27
- /**
28
- * Read configuration from environment variables. Used by
29
- * {@link createConcurrencyBackend} when the user opts into NATS KV.
30
- */
31
- export function readNatsKvConfigFromEnv() {
32
- const serversRaw = process.env.BLOK_CONCURRENCY_NATS_SERVERS ?? "nats://localhost:4222";
33
- const servers = serversRaw
34
- .split(",")
35
- .map((s) => s.trim())
36
- .filter(Boolean);
37
- return {
38
- servers,
39
- token: process.env.BLOK_CONCURRENCY_NATS_TOKEN,
40
- user: process.env.BLOK_CONCURRENCY_NATS_USER,
41
- pass: process.env.BLOK_CONCURRENCY_NATS_PASS,
42
- bucketName: process.env.BLOK_CONCURRENCY_NATS_KV_BUCKET ?? DEFAULT_BUCKET_NAME,
43
- };
44
- }
45
- export class NatsKvConcurrencyBackend {
46
- name = "nats-kv";
47
- nc = null;
48
- kv = null;
49
- config;
50
- connected = false;
51
- constructor(config) {
52
- const env = readNatsKvConfigFromEnv();
53
- this.config = {
54
- servers: config?.servers ?? env.servers,
55
- token: config?.token ?? env.token,
56
- user: config?.user ?? env.user,
57
- pass: config?.pass ?? env.pass,
58
- bucketName: config?.bucketName ?? env.bucketName,
59
- };
60
- }
61
- async connect() {
62
- if (this.connected)
63
- return;
64
- // Security review FW-5 — refuse to start in production with the
65
- // default bucket name. Two deployments sharing a NATS server with
66
- // the default would contend on the same `(workflow, key)` buckets,
67
- // silently corrupting concurrency state across tenants. The fix
68
- // is operator-mandatory: set BLOK_CONCURRENCY_NATS_KV_BUCKET
69
- // per-deployment.
70
- const blokEnv = process.env.BLOK_ENV;
71
- const nodeEnv = process.env.NODE_ENV;
72
- const isProd = blokEnv === "production" || nodeEnv === "production";
73
- if (isProd && this.config.bucketName === DEFAULT_BUCKET_NAME) {
74
- throw new Error(`[blok] NATS KV concurrency backend refuses to start in production with the default bucket name ('${DEFAULT_BUCKET_NAME}'). Set BLOK_CONCURRENCY_NATS_KV_BUCKET to a deployment-unique value (e.g. 'blok-concurrency-acme-prod') to prevent cross-deployment collision on a shared NATS server.`);
75
- }
76
- let natsModule;
77
- try {
78
- natsModule = (await import("nats"));
79
- }
80
- catch (err) {
81
- throw new Error(`NatsKvConcurrencyBackend requires the 'nats' package. Install it: \`bun add nats\` or \`npm install nats\`. Underlying error: ${err instanceof Error ? err.message : String(err)}`);
82
- }
83
- const connectOpts = { servers: this.config.servers };
84
- if (this.config.token)
85
- connectOpts.token = this.config.token;
86
- if (this.config.user)
87
- connectOpts.user = this.config.user;
88
- if (this.config.pass)
89
- connectOpts.pass = this.config.pass;
90
- this.nc = await natsModule.connect(connectOpts);
91
- // nats.js v2.x — KV lives at `nc.jetstream().views.kv(name)`. The
92
- // returned `KV` auto-creates the bucket on first use given the
93
- // connection has KV bucket-create permission. (Earlier versions
94
- // exposed `nc.kv(name)` directly; that API was removed.)
95
- const js = this.nc.jetstream();
96
- this.kv = await js.views.kv(this.config.bucketName);
97
- this.connected = true;
98
- }
99
- async disconnect() {
100
- if (!this.connected)
101
- return;
102
- try {
103
- await this.nc?.drain();
104
- }
105
- finally {
106
- this.nc = null;
107
- this.kv = null;
108
- this.connected = false;
109
- }
110
- }
111
- bucketKey(workflowName, concurrencyKey) {
112
- // Use `__` (double underscore) — KV keys cannot contain `.` or
113
- // `>` per NATS subject grammar; `__` is unambiguous and allows
114
- // arbitrary workflow / key strings.
115
- return `${this.encodeSegment(workflowName)}__${this.encodeSegment(concurrencyKey)}`;
116
- }
117
- encodeSegment(s) {
118
- // NATS KV keys must match `[-/_=\.a-zA-Z0-9]+`. Replace anything
119
- // outside the safe set with hex escape `_HHHH_` to keep the
120
- // roundtrip lossless.
121
- return s.replace(/[^-_=.a-zA-Z0-9]/g, (ch) => `_${ch.codePointAt(0)?.toString(16)}_`);
122
- }
123
- requireKv() {
124
- if (!this.kv) {
125
- throw new Error("NatsKvConcurrencyBackend not connected — call connect() first.");
126
- }
127
- return this.kv;
128
- }
129
- async acquireSlot(workflowName, concurrencyKey, concurrencyLimit, runId, leaseExpiresAt) {
130
- const kv = this.requireKv();
131
- const bucketKey = this.bucketKey(workflowName, concurrencyKey);
132
- // PR 3 D2 — record OCC retry depth + outcome on every exit path.
133
- const metricAttrs = { workflow_name: workflowName, concurrency_key: concurrencyKey };
134
- for (let attempt = 0; attempt < MAX_CAS_RETRIES; attempt++) {
135
- const entry = await this.safeGet(kv, bucketKey);
136
- // PR 2 A6 — fetch failure (broker unreachable / non-NotFound
137
- // error). Spinning 10× CAS retries on a connection problem just
138
- // burns latency. Fail-fast so the trigger sees the issue and
139
- // can fall back / alert. Existing run continues with no slot;
140
- // the gate is conservative.
141
- if (entry === "fetch-failed") {
142
- console.warn(`[blok][concurrency][nats-kv] acquireSlot fetch-failed for ${workflowName}:${concurrencyKey} (attempt ${attempt + 1}); failing closed`);
143
- ConcurrencyMetrics.getInstance().recordOccRetries({ ...metricAttrs, outcome: "fail-closed" }, attempt);
144
- return { acquired: false, currentInFlight: -1 };
145
- }
146
- if (!entry) {
147
- // Bucket doesn't exist — create with first lease.
148
- const initial = { leases: [{ runId, expiresAt: leaseExpiresAt }] };
149
- try {
150
- await kv.create(bucketKey, JSON.stringify(initial));
151
- ConcurrencyMetrics.getInstance().recordOccRetries({ ...metricAttrs, outcome: "success" }, attempt);
152
- return { acquired: true, currentInFlight: 1 };
153
- }
154
- catch {
155
- // Race — another process created. Retry.
156
- continue;
157
- }
158
- }
159
- // Read current state, lazy-purge expired.
160
- const current = this.parseBucket(entry);
161
- const now = Date.now();
162
- const active = current.leases.filter((l) => l.expiresAt > now);
163
- // Idempotent re-acquire: refresh lease, don't grow count.
164
- const existingIdx = active.findIndex((l) => l.runId === runId);
165
- if (existingIdx >= 0) {
166
- active[existingIdx] = { runId, expiresAt: leaseExpiresAt };
167
- try {
168
- await kv.update(bucketKey, JSON.stringify({ leases: active }), entry.revision);
169
- ConcurrencyMetrics.getInstance().recordOccRetries({ ...metricAttrs, outcome: "success" }, attempt);
170
- return { acquired: true, currentInFlight: active.length };
171
- }
172
- catch {
173
- continue;
174
- }
175
- }
176
- // Limit check.
177
- if (active.length >= concurrencyLimit) {
178
- ConcurrencyMetrics.getInstance().recordOccRetries({ ...metricAttrs, outcome: "denied" }, attempt);
179
- return { acquired: false, currentInFlight: active.length };
180
- }
181
- // Insert + CAS.
182
- const updated = { leases: [...active, { runId, expiresAt: leaseExpiresAt }] };
183
- try {
184
- await kv.update(bucketKey, JSON.stringify(updated), entry.revision);
185
- ConcurrencyMetrics.getInstance().recordOccRetries({ ...metricAttrs, outcome: "success" }, attempt);
186
- return { acquired: true, currentInFlight: updated.leases.length };
187
- }
188
- catch { }
189
- }
190
- // Retry exhausted — fail-closed.
191
- console.warn(`[blok][concurrency][nats-kv] acquireSlot exhausted ${MAX_CAS_RETRIES} CAS retries for ${workflowName}:${concurrencyKey}; denying slot to runId=${runId}`);
192
- ConcurrencyMetrics.getInstance().recordOccRetries({ ...metricAttrs, outcome: "fail-closed" }, MAX_CAS_RETRIES);
193
- return { acquired: false, currentInFlight: -1 };
194
- }
195
- async releaseSlot(workflowName, concurrencyKey, runId) {
196
- const kv = this.requireKv();
197
- const bucketKey = this.bucketKey(workflowName, concurrencyKey);
198
- for (let attempt = 0; attempt < MAX_CAS_RETRIES; attempt++) {
199
- const entry = await this.safeGet(kv, bucketKey);
200
- // PR 2 A6 — fetch failure on release. Lease will expire via
201
- // TTL; safe to fail-fast.
202
- if (entry === "fetch-failed") {
203
- console.warn(`[blok][concurrency][nats-kv] releaseSlot fetch-failed for ${workflowName}:${concurrencyKey} (attempt ${attempt + 1}); lease for runId=${runId} will expire via TTL`);
204
- return;
205
- }
206
- if (!entry)
207
- return; // Idempotent — bucket already gone.
208
- const current = this.parseBucket(entry);
209
- const next = current.leases.filter((l) => l.runId !== runId);
210
- // No-op when the runId wasn't holding a slot.
211
- if (next.length === current.leases.length)
212
- return;
213
- if (next.length === 0) {
214
- try {
215
- await kv.delete(bucketKey);
216
- return;
217
- }
218
- catch {
219
- // Another process beat us to delete — fine.
220
- return;
221
- }
222
- }
223
- try {
224
- await kv.update(bucketKey, JSON.stringify({ leases: next }), entry.revision);
225
- return;
226
- }
227
- catch { }
228
- }
229
- console.warn(`[blok][concurrency][nats-kv] releaseSlot exhausted ${MAX_CAS_RETRIES} CAS retries for ${workflowName}:${concurrencyKey}; lease for runId=${runId} will expire via TTL`);
230
- }
231
- async purgeExpired(now) {
232
- const kv = this.requireKv();
233
- let purged = 0;
234
- // **DRAIN THE ITERATOR FIRST.** nats.js v2.x `kv.keys()` returns a
235
- // `QueuedIterator` backed by a JetStream watch consumer. Calling
236
- // `kv.get()` mid-iteration interferes with the iterator's internal
237
- // state — observed in practice that subsequent yields silently
238
- // drop. Collect every key into an array before doing per-key
239
- // reads, then operate on the array.
240
- const allKeys = [];
241
- for await (const key of await kv.keys()) {
242
- allKeys.push(key);
243
- }
244
- for (const key of allKeys) {
245
- const entry = await this.safeGet(kv, key);
246
- // Treat both legitimate misses and fetch failures as "skip
247
- // this bucket" — purge is a best-effort sweep.
248
- if (!entry || entry === "fetch-failed")
249
- continue;
250
- const current = this.parseBucket(entry);
251
- const active = current.leases.filter((l) => l.expiresAt > now);
252
- const expired = current.leases.length - active.length;
253
- if (expired === 0)
254
- continue;
255
- if (active.length === 0) {
256
- try {
257
- await kv.delete(key);
258
- purged += expired;
259
- }
260
- catch {
261
- // best-effort
262
- }
263
- continue;
264
- }
265
- try {
266
- await kv.update(key, JSON.stringify({ leases: active }), entry.revision);
267
- purged += expired;
268
- }
269
- catch {
270
- // CAS conflict — leave for next sweep.
271
- }
272
- }
273
- return purged;
274
- }
275
- /**
276
- * PR 2 A6 — distinguishes legitimate "key not found" from "broker
277
- * unreachable / non-NotFound error". Returns:
278
- * - `NatsKvEntry` on a successful fetch.
279
- * - `null` when the key doesn't exist (NotFound code or null entry).
280
- * - `"fetch-failed"` for any other error (transient broker outage,
281
- * auth failure, network blip, etc.) so the OCC loop can fail-fast
282
- * instead of spinning 10× before fail-closing.
283
- */
284
- async safeGet(kv, key) {
285
- try {
286
- const e = await kv.get(key);
287
- return e ?? null;
288
- }
289
- catch (err) {
290
- // NATS surfaces "not found" via a code. Different `nats`
291
- // package versions use different shapes; cover the common ones.
292
- const code = err.code;
293
- if (code === "NotFound" || code === "404")
294
- return null;
295
- return "fetch-failed";
296
- }
297
- }
298
- parseBucket(entry) {
299
- try {
300
- const parsed = JSON.parse(entry.string());
301
- if (!parsed || !Array.isArray(parsed.leases))
302
- return { leases: [] };
303
- return parsed;
304
- }
305
- catch {
306
- return { leases: [] };
307
- }
308
- }
309
- }
310
- //# sourceMappingURL=NatsKvConcurrencyBackend.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"NatsKvConcurrencyBackend.js","sourceRoot":"","sources":["../../src/concurrency/NatsKvConcurrencyBackend.ts"],"names":[],"mappings":"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"}
@@ -1,64 +0,0 @@
1
- /**
2
- * Tier C #4 follow-up · Redis-backed concurrency backend.
3
- *
4
- * Coordinates per-(workflow, concurrencyKey) lease state across processes
5
- * via a single Redis key per bucket. Atomicity comes from server-side Lua
6
- * scripts — `EVAL` runs single-threaded against the keyspace, so the
7
- * read → filter → check-limit → write sequence is a single round-trip
8
- * with no OCC retry loop (the headline win over the NATS KV backend's
9
- * `WATCH`/`MULTI`/`EXEC`-style optimistic concurrency).
10
- *
11
- * Storage model: one Redis string key per `(workflowName, concurrencyKey)`
12
- * bucket. Value is a JSON-encoded `{leases: [{runId, expiresAt}]}`
13
- * document. Bounded-cardinality assumption identical to NATS KV — typical
14
- * concurrency keys hold 1-50 active leases.
15
- *
16
- * Lease leak: each lease carries an `expiresAt`. Expired leases are
17
- * lazy-purged inside the Lua script that observes them; an explicit
18
- * `purgeExpired` SCAN sweep is also exposed for janitor use.
19
- *
20
- * Connection: ioredis is loaded via dynamic `import("ioredis")` so the
21
- * dependency stays optional. Matches the existing pattern used by
22
- * `triggers/worker`'s `RedisStreamsAdapter` and
23
- * `triggers/pubsub`'s `RedisStreamsPubSubAdapter`.
24
- */
25
- import type { ConcurrencySlotResult } from "../tracing/types";
26
- import type { ConcurrencyBackend } from "./ConcurrencyBackend";
27
- export interface RedisConcurrencyConfig {
28
- /** Full Redis connection URL (e.g. `redis://[user:pass@]host:port[/db]`). Takes precedence over host/port. */
29
- url?: string;
30
- host?: string;
31
- port?: number;
32
- password?: string;
33
- username?: string;
34
- db?: number;
35
- tls?: boolean;
36
- /** Namespace prefix for every Redis key the backend touches. */
37
- keyPrefix: string;
38
- }
39
- /**
40
- * Read configuration from environment variables. Used by
41
- * {@link createConcurrencyBackend} when the operator opts into Redis.
42
- */
43
- export declare function readRedisConfigFromEnv(): RedisConcurrencyConfig;
44
- export declare class RedisConcurrencyBackend implements ConcurrencyBackend {
45
- readonly name = "redis";
46
- private client;
47
- private readonly config;
48
- private connected;
49
- constructor(config?: Partial<RedisConcurrencyConfig>);
50
- connect(): Promise<void>;
51
- disconnect(): Promise<void>;
52
- private bucketKey;
53
- private encodeSegment;
54
- private requireClient;
55
- acquireSlot(workflowName: string, concurrencyKey: string, concurrencyLimit: number, runId: string, leaseExpiresAt: number): Promise<ConcurrencySlotResult>;
56
- releaseSlot(workflowName: string, concurrencyKey: string, runId: string): Promise<void>;
57
- purgeExpired(now: number): Promise<number>;
58
- /**
59
- * Decode the `{acquired, currentInFlight}` pair from a Lua eval result.
60
- * ioredis returns Redis arrays as plain JS arrays of (string | number)
61
- * — the script returns integers, so both elements should be numbers.
62
- */
63
- private parsePair;
64
- }