bunqueue 2.8.49 → 2.8.50

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 (129) hide show
  1. package/README.md +19 -9
  2. package/dist/application/contextFactory.d.ts +4 -2
  3. package/dist/application/contextFactory.js +3 -0
  4. package/dist/application/flowFailureRecovery.d.ts +17 -0
  5. package/dist/application/flowFailureRecovery.js +92 -0
  6. package/dist/application/operations/ack.d.ts +3 -2
  7. package/dist/application/operations/ack.js +34 -8
  8. package/dist/application/operations/flowPush.d.ts +9 -0
  9. package/dist/application/operations/flowPush.js +112 -0
  10. package/dist/application/operations/flowTopologyValidation.d.ts +3 -0
  11. package/dist/application/operations/flowTopologyValidation.js +101 -0
  12. package/dist/application/operations/flowValidation.d.ts +3 -0
  13. package/dist/application/operations/flowValidation.js +166 -0
  14. package/dist/application/operations/push.d.ts +3 -0
  15. package/dist/application/operations/push.js +2 -2
  16. package/dist/application/operations/pushInsert.d.ts +7 -1
  17. package/dist/application/operations/pushInsert.js +18 -8
  18. package/dist/application/operations/pushLocks.d.ts +1 -0
  19. package/dist/application/operations/pushLocks.js +5 -1
  20. package/dist/application/operations/queryOperations.js +7 -6
  21. package/dist/application/queueManager.d.ts +5 -0
  22. package/dist/application/queueManager.js +195 -60
  23. package/dist/cli/commandRouter.d.ts +1 -1
  24. package/dist/client/flow.d.ts +3 -6
  25. package/dist/client/flow.js +71 -210
  26. package/dist/client/flowAtomic.d.ts +9 -0
  27. package/dist/client/flowAtomic.js +24 -0
  28. package/dist/client/flowJobCoreMethods.d.ts +28 -0
  29. package/dist/client/flowJobCoreMethods.js +151 -0
  30. package/dist/client/flowJobDependencies.d.ts +7 -0
  31. package/dist/client/flowJobDependencies.js +64 -0
  32. package/dist/client/flowJobFactory.d.ts +11 -24
  33. package/dist/client/flowJobFactory.js +91 -360
  34. package/dist/client/flowJobMoveMethods.d.ts +16 -0
  35. package/dist/client/flowJobMoveMethods.js +112 -0
  36. package/dist/client/flowJobTypes.d.ts +29 -0
  37. package/dist/client/flowJobTypes.js +6 -0
  38. package/dist/client/flowLegacyPlan.d.ts +16 -0
  39. package/dist/client/flowLegacyPlan.js +118 -0
  40. package/dist/client/flowOptions.d.ts +10 -0
  41. package/dist/client/flowOptions.js +44 -0
  42. package/dist/client/flowPlan.d.ts +16 -0
  43. package/dist/client/flowPlan.js +93 -0
  44. package/dist/client/flowPush.js +4 -1
  45. package/dist/client/flowReader.d.ts +10 -0
  46. package/dist/client/flowReader.js +147 -0
  47. package/dist/client/jobHelpers.js +2 -0
  48. package/dist/client/workflow/clock.d.ts +3 -1
  49. package/dist/client/workflow/clock.js +18 -1
  50. package/dist/client/workflow/compensationChild.d.ts +30 -0
  51. package/dist/client/workflow/compensationChild.js +65 -0
  52. package/dist/client/workflow/compensationPass.d.ts +16 -0
  53. package/dist/client/workflow/compensationPass.js +96 -0
  54. package/dist/client/workflow/compensationSupport.d.ts +24 -0
  55. package/dist/client/workflow/compensationSupport.js +57 -0
  56. package/dist/client/workflow/compensator.d.ts +11 -50
  57. package/dist/client/workflow/compensator.js +22 -374
  58. package/dist/client/workflow/definitionGuard.d.ts +11 -0
  59. package/dist/client/workflow/definitionGuard.js +22 -0
  60. package/dist/client/workflow/engine.d.ts +2 -2
  61. package/dist/client/workflow/engine.js +8 -8
  62. package/dist/client/workflow/eventTypes.d.ts +44 -0
  63. package/dist/client/workflow/eventTypes.js +2 -0
  64. package/dist/client/workflow/executionTypes.d.ts +133 -0
  65. package/dist/client/workflow/executionTypes.js +2 -0
  66. package/dist/client/workflow/executor.d.ts +4 -17
  67. package/dist/client/workflow/executor.js +50 -208
  68. package/dist/client/workflow/executorLifecycle.d.ts +18 -0
  69. package/dist/client/workflow/executorLifecycle.js +69 -0
  70. package/dist/client/workflow/executorNodes.d.ts +17 -0
  71. package/dist/client/workflow/executorNodes.js +138 -0
  72. package/dist/client/workflow/identity.d.ts +2 -0
  73. package/dist/client/workflow/identity.js +8 -0
  74. package/dist/client/workflow/index.d.ts +1 -1
  75. package/dist/client/workflow/loops.d.ts +3 -5
  76. package/dist/client/workflow/loops.js +25 -23
  77. package/dist/client/workflow/mapRunner.d.ts +4 -0
  78. package/dist/client/workflow/mapRunner.js +45 -0
  79. package/dist/client/workflow/recovery.js +10 -3
  80. package/dist/client/workflow/runner.d.ts +2 -21
  81. package/dist/client/workflow/runner.js +39 -104
  82. package/dist/client/workflow/runnerTiming.d.ts +14 -0
  83. package/dist/client/workflow/runnerTiming.js +66 -0
  84. package/dist/client/workflow/stepTypes.d.ts +171 -0
  85. package/dist/client/workflow/stepTypes.js +3 -0
  86. package/dist/client/workflow/store.d.ts +17 -17
  87. package/dist/client/workflow/store.js +65 -100
  88. package/dist/client/workflow/storeExecutionCodec.d.ts +11 -0
  89. package/dist/client/workflow/storeExecutionCodec.js +34 -0
  90. package/dist/client/workflow/storeListing.d.ts +11 -0
  91. package/dist/client/workflow/storeListing.js +45 -0
  92. package/dist/client/workflow/storeMaintenance.d.ts +4 -0
  93. package/dist/client/workflow/storeMaintenance.js +40 -0
  94. package/dist/client/workflow/storeSignals.d.ts +9 -0
  95. package/dist/client/workflow/storeSignals.js +38 -2
  96. package/dist/client/workflow/subWorkflowRunner.d.ts +13 -0
  97. package/dist/client/workflow/subWorkflowRunner.js +40 -0
  98. package/dist/client/workflow/types.d.ts +4 -356
  99. package/dist/client/workflow/types.js +1 -3
  100. package/dist/client/workflow/waitFor.js +39 -26
  101. package/dist/client/workflow/workflow.d.ts +16 -59
  102. package/dist/client/workflow/workflow.js +53 -179
  103. package/dist/client/workflow/workflowDecisions.d.ts +11 -0
  104. package/dist/client/workflow/workflowDecisions.js +27 -0
  105. package/dist/client/workflow/workflowDefinition.d.ts +16 -0
  106. package/dist/client/workflow/workflowDefinition.js +123 -0
  107. package/dist/client/workflow/workflowIntrospection.d.ts +5 -0
  108. package/dist/client/workflow/workflowIntrospection.js +46 -0
  109. package/dist/client/workflow/workflowValidation.d.ts +44 -0
  110. package/dist/client/workflow/workflowValidation.js +143 -0
  111. package/dist/domain/types/command.d.ts +7 -1
  112. package/dist/domain/types/flow.d.ts +25 -0
  113. package/dist/domain/types/flow.js +1 -0
  114. package/dist/infrastructure/persistence/schema.d.ts +2 -2
  115. package/dist/infrastructure/persistence/schema.js +52 -3
  116. package/dist/infrastructure/persistence/sqlite.d.ts +16 -0
  117. package/dist/infrastructure/persistence/sqlite.js +129 -7
  118. package/dist/infrastructure/persistence/sqliteBatch.js +10 -4
  119. package/dist/infrastructure/persistence/sqliteSerializer.d.ts +2 -0
  120. package/dist/infrastructure/persistence/sqliteSerializer.js +18 -5
  121. package/dist/infrastructure/persistence/statements.d.ts +4 -0
  122. package/dist/infrastructure/persistence/statements.js +8 -2
  123. package/dist/infrastructure/server/handlerRoutes.js +3 -0
  124. package/dist/infrastructure/server/handlers/advanced.js +2 -2
  125. package/dist/infrastructure/server/handlers/flow.d.ts +7 -0
  126. package/dist/infrastructure/server/handlers/flow.js +11 -0
  127. package/dist/infrastructure/server/handlers/index.d.ts +1 -0
  128. package/dist/infrastructure/server/handlers/index.js +1 -0
  129. package/package.json +4 -2
@@ -1,29 +1,16 @@
1
1
  /**
2
2
  * Flow Job Factory
3
- * Creates simple Job objects for FlowProducer results
3
+ * Creates BullMQ-compatible Job objects backed by FlowProducer transports.
4
4
  */
5
+ import type { Job as DomainJob } from '../domain/types/job';
6
+ import type { FlowJobCallbacks } from './flowJobTypes';
5
7
  import type { Job } from './types';
6
- import type { TcpConnectionPool } from './tcpPool';
7
- /** Callbacks for flow job mutation operations */
8
- export interface FlowJobCallbacks {
9
- /** Execution mode — enables full method wiring when provided */
10
- embedded?: boolean;
11
- tcp?: TcpConnectionPool | null;
12
- updateData?: (id: string, data: unknown) => Promise<void>;
13
- updateProgress?: (id: string, progress: number | object) => Promise<void>;
14
- log?: (id: string, message: string) => Promise<void>;
15
- promote?: (id: string) => Promise<void>;
16
- remove?: (id: string) => Promise<void>;
17
- changePriority?: (id: string, opts: {
18
- priority: number;
19
- lifo?: boolean;
20
- }) => Promise<void>;
21
- changeDelay?: (id: string, delay: number) => Promise<void>;
22
- clearLogs?: (id: string) => Promise<void>;
23
- retry?: (id: string) => Promise<void>;
24
- getState?: (id: string) => Promise<string>;
25
- }
26
- /** Extract user data (remove internal fields like __parentId, __childrenIds, name) */
8
+ export type { FlowJobCallbacks } from './flowJobTypes';
9
+ /** Extract user data while removing internal flow metadata and the stored job name. */
27
10
  export declare function extractUserDataFromInternal(data: Record<string, unknown>): unknown;
28
- /** Create a simple Job object for flow results */
29
- export declare function createFlowJobObject<T>(id: string, name: string, data: T, queueName: string, callbacks?: FlowJobCallbacks): Job<T>;
11
+ interface FlowJobObjectOptions {
12
+ callbacks?: FlowJobCallbacks;
13
+ snapshot?: DomainJob;
14
+ }
15
+ /** Create a Job object for a newly committed or fetched flow node. */
16
+ export declare function createFlowJobObject<T>(id: string, name: string, data: T, queueName: string, factoryOptions?: FlowJobObjectOptions): Job<T>;
@@ -1,227 +1,45 @@
1
1
  /**
2
2
  * Flow Job Factory
3
- * Creates simple Job objects for FlowProducer results
3
+ * Creates BullMQ-compatible Job objects backed by FlowProducer transports.
4
4
  */
5
- import { getSharedManager } from './manager';
6
- import { buildFailCommand, failEmbeddedArgs } from './queue/failWire';
7
5
  import { jobId } from '../domain/types/job';
8
- /** Extract user data (remove internal fields like __parentId, __childrenIds, name) */
9
- export function extractUserDataFromInternal(data) {
10
- const result = {};
11
- for (const [key, value] of Object.entries(data)) {
12
- if (!key.startsWith('__') && key !== 'name') {
13
- result[key] = value;
14
- }
6
+ import { buildJobProperties, buildSerializationMethods } from './jobConversionHelpers';
7
+ import { buildJobOpts } from './jobHelpers';
8
+ import { buildFlowJobCoreMethods } from './flowJobCoreMethods';
9
+ import { buildFlowJobMoveMethods } from './flowJobMoveMethods';
10
+ import { getSharedManager } from './manager';
11
+ const JOB_STATES = new Set([
12
+ 'waiting',
13
+ 'active',
14
+ 'completed',
15
+ 'failed',
16
+ 'delayed',
17
+ 'prioritized',
18
+ 'waiting-children',
19
+ 'unknown',
20
+ ]);
21
+ function stateAsType(state) {
22
+ return JOB_STATES.has(state) ? state : 'unknown';
23
+ }
24
+ function buildStateResolver(id, callbacks) {
25
+ if (callbacks?.getState) {
26
+ return () => callbacks.getState(id).then(stateAsType);
15
27
  }
16
- return result;
28
+ if (callbacks?.embedded) {
29
+ return () => getSharedManager().getJobState(jobId(id)).then(stateAsType);
30
+ }
31
+ if (callbacks?.tcp) {
32
+ return () => callbacks.tcp.send({ cmd: 'GetState', id }).then((response) => {
33
+ if (response.ok !== true) {
34
+ throw new Error(typeof response.error === 'string' ? response.error : 'GetState failed');
35
+ }
36
+ return stateAsType(typeof response.state === 'string' ? response.state : 'unknown');
37
+ });
38
+ }
39
+ return () => Promise.resolve('unknown');
17
40
  }
18
- /** Create a simple Job object for flow results */
19
- export function createFlowJobObject(id, name, data, queueName, callbacks) {
20
- const ts = Date.now();
21
- const embedded = !!callbacks?.embedded;
22
- const tcp = callbacks?.tcp ?? null;
23
- const stateAsType = (s) => {
24
- const valid = [
25
- 'waiting',
26
- 'active',
27
- 'completed',
28
- 'failed',
29
- 'delayed',
30
- 'prioritized',
31
- 'waiting-children',
32
- 'unknown',
33
- ];
34
- return (valid.includes(s) ? s : 'unknown');
35
- };
36
- const getStateInternal = () => {
37
- if (callbacks?.getState)
38
- return callbacks.getState(id).then(stateAsType);
39
- if (embedded) {
40
- return getSharedManager()
41
- .getJobState(jobId(id))
42
- .then((s) => stateAsType(s));
43
- }
44
- if (tcp) {
45
- return tcp.send({ cmd: 'GetState', id }).then((r) => {
46
- const s = r.state ?? 'unknown';
47
- return stateAsType(s);
48
- });
49
- }
50
- return Promise.resolve('unknown');
51
- };
41
+ function defaultSerialization(id, name, data, queueName, timestamp) {
52
42
  return {
53
- id,
54
- name,
55
- data,
56
- queueName,
57
- attemptsMade: 0,
58
- timestamp: ts,
59
- progress: 0,
60
- delay: 0,
61
- processedOn: undefined,
62
- finishedOn: undefined,
63
- stacktrace: null,
64
- stalledCounter: 0,
65
- priority: 0,
66
- parentKey: undefined,
67
- opts: {},
68
- token: undefined,
69
- processedBy: undefined,
70
- deduplicationId: undefined,
71
- repeatJobKey: undefined,
72
- attemptsStarted: 0,
73
- updateProgress: async (progress) => {
74
- if (callbacks?.updateProgress) {
75
- return callbacks.updateProgress(id, progress);
76
- }
77
- if (embedded) {
78
- await getSharedManager().updateProgress(jobId(id), progress);
79
- return;
80
- }
81
- if (tcp)
82
- await tcp.send({ cmd: 'Progress', id, progress: progress });
83
- },
84
- log: async (message) => {
85
- if (callbacks?.log)
86
- return callbacks.log(id, message);
87
- if (embedded) {
88
- getSharedManager().addLog(jobId(id), message);
89
- return;
90
- }
91
- if (tcp)
92
- await tcp.send({ cmd: 'AddLog', id, message });
93
- },
94
- getState: getStateInternal,
95
- remove: async () => {
96
- if (callbacks?.remove)
97
- return callbacks.remove(id);
98
- if (embedded) {
99
- await getSharedManager().cancel(jobId(id));
100
- return;
101
- }
102
- if (tcp)
103
- await tcp.send({ cmd: 'Cancel', id });
104
- },
105
- retry: async () => {
106
- if (callbacks?.retry)
107
- return callbacks.retry(id);
108
- if (embedded) {
109
- const mgr = getSharedManager();
110
- const state = await mgr.getJobState(jobId(id));
111
- if (state === 'failed') {
112
- const count = mgr.retryDlq(queueName, jobId(id));
113
- if (count === 0)
114
- throw new Error(`Job ${id} is failed but not present in DLQ`);
115
- return;
116
- }
117
- if (state === 'active') {
118
- const ok = await mgr.moveActiveToWait(jobId(id));
119
- if (!ok)
120
- throw new Error(`Failed to retry active job ${id}`);
121
- return;
122
- }
123
- if (state === 'waiting' || state === 'prioritized' || state === 'delayed')
124
- return;
125
- throw new Error(`Cannot retry job ${id} from state '${state}'`);
126
- }
127
- if (!tcp)
128
- return;
129
- const res = await tcp.send({ cmd: 'MoveToWait', id });
130
- if (res.ok !== true) {
131
- const err = typeof res.error === 'string' ? res.error : 'retry failed';
132
- throw new Error(err);
133
- }
134
- },
135
- getChildrenValues: async () => {
136
- if (embedded) {
137
- return (await getSharedManager().getChildrenValues(jobId(id)));
138
- }
139
- if (!tcp)
140
- return {};
141
- const res = await tcp.send({ cmd: 'GetChildrenValues', id });
142
- const vals = res.data?.values ?? {};
143
- return vals;
144
- },
145
- isWaiting: async () => (await getStateInternal()) === 'waiting',
146
- isActive: async () => (await getStateInternal()) === 'active',
147
- isDelayed: async () => (await getStateInternal()) === 'delayed',
148
- isCompleted: async () => (await getStateInternal()) === 'completed',
149
- isFailed: async () => (await getStateInternal()) === 'failed',
150
- isWaitingChildren: async () => (await getStateInternal()) === 'waiting-children',
151
- updateData: async (newData) => {
152
- if (callbacks?.updateData)
153
- return callbacks.updateData(id, newData);
154
- if (embedded) {
155
- await getSharedManager().updateJobData(jobId(id), newData);
156
- return;
157
- }
158
- if (tcp)
159
- await tcp.send({ cmd: 'Update', id, data: newData });
160
- },
161
- promote: async () => {
162
- if (callbacks?.promote)
163
- return callbacks.promote(id);
164
- if (embedded) {
165
- await getSharedManager().promote(jobId(id));
166
- return;
167
- }
168
- if (tcp)
169
- await tcp.send({ cmd: 'Promote', id });
170
- },
171
- changeDelay: async (delay) => {
172
- if (callbacks?.changeDelay)
173
- return callbacks.changeDelay(id, delay);
174
- if (embedded) {
175
- await getSharedManager().changeDelay(jobId(id), delay);
176
- return;
177
- }
178
- if (tcp)
179
- await tcp.send({ cmd: 'ChangeDelay', id, delay });
180
- },
181
- changePriority: async (opts) => {
182
- if (callbacks?.changePriority) {
183
- return callbacks.changePriority(id, { priority: opts.priority, lifo: opts.lifo });
184
- }
185
- if (embedded) {
186
- await getSharedManager().changePriority(jobId(id), opts.priority, opts.lifo);
187
- return;
188
- }
189
- if (tcp) {
190
- await tcp.send({ cmd: 'ChangePriority', id, priority: opts.priority, lifo: opts.lifo });
191
- }
192
- },
193
- extendLock: async (token, duration) => {
194
- if (embedded) {
195
- const ok = await getSharedManager().extendLock(jobId(id), token, duration);
196
- return ok ? duration : 0;
197
- }
198
- if (!tcp)
199
- return 0;
200
- const res = await tcp.send({ cmd: 'ExtendLock', id, token, duration });
201
- return res.ok === true ? duration : 0;
202
- },
203
- clearLogs: async (keepLogs) => {
204
- if (callbacks?.clearLogs)
205
- return callbacks.clearLogs(id);
206
- if (embedded) {
207
- getSharedManager().clearLogs(jobId(id), keepLogs);
208
- return;
209
- }
210
- if (tcp)
211
- await tcp.send({ cmd: 'ClearLogs', id, keepLogs });
212
- },
213
- getDependencies: async () => {
214
- const childIds = await fetchChildIds(id, embedded, tcp);
215
- return computeDepsFlow(queueName, childIds, embedded, tcp);
216
- },
217
- getDependenciesCount: async () => {
218
- const childIds = await fetchChildIds(id, embedded, tcp);
219
- const deps = await computeDepsFlow(queueName, childIds, embedded, tcp);
220
- return {
221
- processed: Object.keys(deps.processed).length,
222
- unprocessed: deps.unprocessed.length,
223
- };
224
- },
225
43
  toJSON: () => ({
226
44
  id,
227
45
  name,
@@ -229,7 +47,7 @@ export function createFlowJobObject(id, name, data, queueName, callbacks) {
229
47
  opts: {},
230
48
  progress: 0,
231
49
  delay: 0,
232
- timestamp: ts,
50
+ timestamp,
233
51
  attemptsMade: 0,
234
52
  stacktrace: null,
235
53
  queueQualifiedName: `bull:${queueName}`,
@@ -241,153 +59,66 @@ export function createFlowJobObject(id, name, data, queueName, callbacks) {
241
59
  opts: '{}',
242
60
  progress: '0',
243
61
  delay: '0',
244
- timestamp: String(ts),
62
+ timestamp: String(timestamp),
245
63
  attemptsMade: '0',
246
64
  stacktrace: null,
247
65
  }),
248
- moveToCompleted: async (returnValue) => {
249
- if (embedded) {
250
- await getSharedManager().ack(jobId(id), returnValue);
251
- return null;
252
- }
253
- if (tcp)
254
- await tcp.send({ cmd: 'ACK', id, result: returnValue });
255
- return null;
256
- },
257
- moveToFailed: async (error) => {
258
- // Forward stacktrace + UnrecoverableError (was dropped; #74/#111-class).
259
- if (embedded) {
260
- await getSharedManager().fail(jobId(id), ...failEmbeddedArgs(error));
261
- return;
262
- }
263
- if (tcp)
264
- await tcp.send(buildFailCommand(id, error));
265
- },
266
- moveToWait: async () => {
267
- if (embedded)
268
- return await getSharedManager().moveActiveToWait(jobId(id));
269
- if (!tcp)
270
- return false;
271
- const res = await tcp.send({ cmd: 'MoveToWait', id });
272
- return res.ok === true;
273
- },
274
- moveToDelayed: async (timestamp) => {
275
- const delay = Math.max(0, timestamp - Date.now());
276
- if (embedded) {
277
- await getSharedManager().moveToDelayed(jobId(id), delay);
278
- return;
279
- }
280
- if (tcp)
281
- await tcp.send({ cmd: 'MoveToDelayed', id, delay });
282
- },
283
- moveToWaitingChildren: async () => {
284
- if (embedded)
285
- return await getSharedManager().moveToWaitingChildren(jobId(id));
286
- throw new Error('moveToWaitingChildren is not supported in TCP mode — no server command available');
287
- },
288
- waitUntilFinished: async (_qe, ttl) => {
289
- const timeout = ttl ?? 30000;
290
- if (embedded) {
291
- const mgr = getSharedManager();
292
- const job = await mgr.getJob(jobId(id));
293
- if (!job)
294
- throw new Error(`Job ${id} not found`);
295
- if (job.completedAt)
296
- return mgr.getResult(jobId(id));
297
- const ok = await mgr.waitForJobCompletion(jobId(id), timeout);
298
- if (!ok)
299
- throw new Error(`waitUntilFinished timed out after ${timeout}ms`);
300
- return mgr.getResult(jobId(id));
301
- }
302
- if (!tcp)
303
- throw new Error('waitUntilFinished: no connection');
304
- const res = await tcp.send({ cmd: 'WaitJob', id, timeout });
305
- const typed = res;
306
- if (!typed.completed)
307
- throw new Error(`waitUntilFinished timed out after ${timeout}ms`);
308
- return typed.result;
309
- },
310
- discard: () => {
311
- if (embedded) {
312
- void getSharedManager().discard(jobId(id));
313
- return;
314
- }
315
- if (tcp)
316
- void tcp.send({ cmd: 'Discard', id });
317
- },
318
- getFailedChildrenValues: async () => {
319
- if (embedded)
320
- return await getSharedManager().getFailedChildrenValues(jobId(id));
321
- if (!tcp)
322
- return {};
323
- const res = await tcp.send({ cmd: 'GetFailedChildrenValues', id });
324
- return res.values ?? {};
325
- },
326
- getIgnoredChildrenFailures: async () => {
327
- if (embedded)
328
- return await getSharedManager().getIgnoredChildrenFailures(jobId(id));
329
- if (!tcp)
330
- return {};
331
- const res = await tcp.send({ cmd: 'GetIgnoredChildrenFailures', id });
332
- return res.values ?? {};
333
- },
334
- removeChildDependency: async () => {
335
- if (embedded)
336
- return await getSharedManager().removeChildDependency(jobId(id));
337
- if (!tcp)
338
- return false;
339
- const res = await tcp.send({ cmd: 'RemoveChildDependency', id });
340
- return res.removed ?? false;
341
- },
342
- removeDeduplicationKey: () => Promise.reject(new Error('removeDeduplicationKey is not implemented — no server primitive available')),
343
- removeUnprocessedChildren: async () => {
344
- if (embedded) {
345
- await getSharedManager().removeUnprocessedChildren(jobId(id));
346
- return;
347
- }
348
- if (tcp)
349
- await tcp.send({ cmd: 'RemoveUnprocessedChildren', id });
350
- },
351
66
  };
352
67
  }
353
- async function fetchChildIds(id, embedded, tcp) {
354
- if (embedded) {
355
- const job = await getSharedManager().getJob(jobId(id));
356
- return (job?.childrenIds ?? []).map(String);
68
+ /** Extract user data while removing internal flow metadata and the stored job name. */
69
+ export function extractUserDataFromInternal(data) {
70
+ const result = {};
71
+ for (const [key, value] of Object.entries(data)) {
72
+ if (!key.startsWith('__') && key !== 'name')
73
+ result[key] = value;
357
74
  }
358
- if (!tcp)
359
- return [];
360
- const jobRes = await tcp.send({ cmd: 'GetJob', id });
361
- const parent = jobRes.job;
362
- return (parent?.childrenIds ?? []).map(String);
75
+ return result;
363
76
  }
364
- async function computeDepsFlow(queueName, childIds, embedded, tcp) {
365
- const processed = {};
366
- const unprocessed = [];
367
- for (const cid of childIds) {
368
- let state = 'unknown';
369
- let result;
370
- if (embedded) {
371
- const mgr = getSharedManager();
372
- state = await mgr.getJobState(jobId(cid));
373
- if (state === 'completed')
374
- result = mgr.getResult(jobId(cid));
375
- }
376
- else if (tcp) {
377
- const r = await tcp.send({ cmd: 'GetState', id: cid });
378
- state = r.state ?? 'unknown';
379
- if (state === 'completed') {
380
- const rr = await tcp.send({ cmd: 'GetResult', id: cid });
381
- result = rr.result;
382
- }
383
- }
384
- const key = `${queueName}:${cid}`;
385
- if (state === 'completed' || state === 'failed') {
386
- processed[key] = result ?? null;
387
- }
388
- else {
389
- unprocessed.push(key);
390
- }
391
- }
392
- return { processed, unprocessed };
77
+ /** Create a Job object for a newly committed or fetched flow node. */
78
+ export function createFlowJobObject(id, name, data, queueName, factoryOptions = {}) {
79
+ const { callbacks, snapshot } = factoryOptions;
80
+ const timestamp = Date.now();
81
+ const runtime = {
82
+ id,
83
+ queueName,
84
+ callbacks,
85
+ embedded: callbacks?.embedded === true,
86
+ tcp: callbacks?.tcp ?? null,
87
+ getState: buildStateResolver(id, callbacks),
88
+ };
89
+ const result = {
90
+ id,
91
+ name,
92
+ data,
93
+ queueName,
94
+ attemptsMade: 0,
95
+ timestamp,
96
+ progress: 0,
97
+ delay: 0,
98
+ processedOn: undefined,
99
+ finishedOn: undefined,
100
+ stacktrace: null,
101
+ stalledCounter: 0,
102
+ priority: 0,
103
+ parentKey: undefined,
104
+ opts: {},
105
+ token: undefined,
106
+ processedBy: undefined,
107
+ deduplicationId: undefined,
108
+ repeatJobKey: undefined,
109
+ attemptsStarted: 0,
110
+ ...buildFlowJobCoreMethods(runtime),
111
+ ...defaultSerialization(id, name, data, queueName, timestamp),
112
+ ...buildFlowJobMoveMethods(runtime),
113
+ };
114
+ if (!snapshot)
115
+ return result;
116
+ const options = buildJobOpts(snapshot);
117
+ Object.assign(result, buildJobProperties(snapshot, name), { data, opts: options });
118
+ const serialization = buildSerializationMethods(snapshot, id, name, options);
119
+ Object.assign(result, {
120
+ toJSON: () => ({ ...serialization.toJSON(), data }),
121
+ asJSON: () => ({ ...serialization.asJSON(), data: JSON.stringify(data) }),
122
+ });
123
+ return result;
393
124
  }
@@ -0,0 +1,16 @@
1
+ import { type FlowJobRuntime } from './flowJobTypes';
2
+ /** Lifecycle and failure-inspection methods exposed by a FlowProducer Job. */
3
+ export declare function buildFlowJobMoveMethods(runtime: FlowJobRuntime): {
4
+ moveToCompleted: (returnValue: unknown) => Promise<null>;
5
+ moveToFailed: (error: Error) => Promise<void>;
6
+ moveToWait: () => Promise<boolean>;
7
+ moveToDelayed: (timestamp: number) => Promise<undefined>;
8
+ moveToWaitingChildren: () => Promise<boolean>;
9
+ waitUntilFinished: (_queueEvents: unknown, ttl?: number) => Promise<unknown>;
10
+ discard: () => void;
11
+ getFailedChildrenValues: () => Promise<Record<string, string>>;
12
+ getIgnoredChildrenFailures: () => Promise<Record<string, string>>;
13
+ removeChildDependency: () => Promise<boolean>;
14
+ removeDeduplicationKey: () => Promise<boolean>;
15
+ removeUnprocessedChildren: () => Promise<undefined>;
16
+ };
@@ -0,0 +1,112 @@
1
+ import { jobId } from '../domain/types/job';
2
+ import { getSharedManager } from './manager';
3
+ import { buildFailCommand, failEmbeddedArgs } from './queue/failWire';
4
+ import { assertFlowTcpOk } from './flowJobTypes';
5
+ /** Lifecycle and failure-inspection methods exposed by a FlowProducer Job. */
6
+ export function buildFlowJobMoveMethods(runtime) {
7
+ const { id, embedded, tcp } = runtime;
8
+ return {
9
+ moveToCompleted: async (returnValue) => {
10
+ if (embedded) {
11
+ await getSharedManager().ack(jobId(id), returnValue);
12
+ return null;
13
+ }
14
+ if (tcp)
15
+ assertFlowTcpOk(await tcp.send({ cmd: 'ACK', id, result: returnValue }), 'ACK');
16
+ return null;
17
+ },
18
+ moveToFailed: async (error) => {
19
+ if (embedded) {
20
+ await getSharedManager().fail(jobId(id), ...failEmbeddedArgs(error));
21
+ return;
22
+ }
23
+ if (tcp)
24
+ assertFlowTcpOk(await tcp.send(buildFailCommand(id, error)), 'FAIL');
25
+ },
26
+ moveToWait: async () => {
27
+ if (embedded)
28
+ return getSharedManager().moveActiveToWait(jobId(id));
29
+ if (!tcp)
30
+ return false;
31
+ assertFlowTcpOk(await tcp.send({ cmd: 'MoveToWait', id }), 'MoveToWait');
32
+ return true;
33
+ },
34
+ moveToDelayed: async (timestamp) => {
35
+ const delay = Math.max(0, timestamp - Date.now());
36
+ if (embedded)
37
+ return void (await getSharedManager().moveToDelayed(jobId(id), delay));
38
+ if (!tcp)
39
+ return;
40
+ assertFlowTcpOk(await tcp.send({ cmd: 'MoveToDelayed', id, delay }), 'MoveToDelayed');
41
+ },
42
+ moveToWaitingChildren: async () => {
43
+ if (embedded)
44
+ return getSharedManager().moveToWaitingChildren(jobId(id));
45
+ throw new Error('moveToWaitingChildren is not supported in TCP mode — no server command available');
46
+ },
47
+ waitUntilFinished: async (_queueEvents, ttl) => {
48
+ const timeout = ttl ?? 30_000;
49
+ if (embedded) {
50
+ const manager = getSharedManager();
51
+ const job = await manager.getJob(jobId(id));
52
+ if (!job)
53
+ throw new Error(`Job ${id} not found`);
54
+ if (job.completedAt)
55
+ return manager.getResult(jobId(id));
56
+ if (!(await manager.waitForJobCompletion(jobId(id), timeout))) {
57
+ throw new Error(`waitUntilFinished timed out after ${timeout}ms`);
58
+ }
59
+ return manager.getResult(jobId(id));
60
+ }
61
+ if (!tcp)
62
+ throw new Error('waitUntilFinished: no connection');
63
+ const response = await tcp.send({ cmd: 'WaitJob', id, timeout });
64
+ assertFlowTcpOk(response, 'WaitJob');
65
+ const typed = response;
66
+ if (!typed.completed)
67
+ throw new Error(`waitUntilFinished timed out after ${timeout}ms`);
68
+ return typed.result;
69
+ },
70
+ discard: () => {
71
+ if (embedded)
72
+ void getSharedManager().discard(jobId(id));
73
+ else if (tcp)
74
+ void tcp.send({ cmd: 'Discard', id });
75
+ },
76
+ getFailedChildrenValues: async () => {
77
+ if (embedded)
78
+ return getSharedManager().getFailedChildrenValues(jobId(id));
79
+ if (!tcp)
80
+ return {};
81
+ const response = await tcp.send({ cmd: 'GetFailedChildrenValues', id });
82
+ assertFlowTcpOk(response, 'GetFailedChildrenValues');
83
+ return response.values ?? {};
84
+ },
85
+ getIgnoredChildrenFailures: async () => {
86
+ if (embedded)
87
+ return getSharedManager().getIgnoredChildrenFailures(jobId(id));
88
+ if (!tcp)
89
+ return {};
90
+ const response = await tcp.send({ cmd: 'GetIgnoredChildrenFailures', id });
91
+ assertFlowTcpOk(response, 'GetIgnoredChildrenFailures');
92
+ return response.values ?? {};
93
+ },
94
+ removeChildDependency: async () => {
95
+ if (embedded)
96
+ return getSharedManager().removeChildDependency(jobId(id));
97
+ if (!tcp)
98
+ return false;
99
+ const response = await tcp.send({ cmd: 'RemoveChildDependency', id });
100
+ assertFlowTcpOk(response, 'RemoveChildDependency');
101
+ return response.removed ?? false;
102
+ },
103
+ removeDeduplicationKey: () => Promise.reject(new Error('removeDeduplicationKey is not implemented — no server primitive available')),
104
+ removeUnprocessedChildren: async () => {
105
+ if (embedded)
106
+ return void (await getSharedManager().removeUnprocessedChildren(jobId(id)));
107
+ if (!tcp)
108
+ return;
109
+ assertFlowTcpOk(await tcp.send({ cmd: 'RemoveUnprocessedChildren', id }), 'RemoveUnprocessedChildren');
110
+ },
111
+ };
112
+ }
@@ -0,0 +1,29 @@
1
+ import type { JobStateType } from './types';
2
+ import type { TcpConnectionPool } from './tcpPool';
3
+ /** Callbacks used to wire FlowProducer Job mutations to the selected transport. */
4
+ export interface FlowJobCallbacks {
5
+ embedded?: boolean;
6
+ tcp?: TcpConnectionPool | null;
7
+ updateData?: (id: string, data: unknown) => Promise<void>;
8
+ updateProgress?: (id: string, progress: number | object) => Promise<void>;
9
+ log?: (id: string, message: string) => Promise<void>;
10
+ promote?: (id: string) => Promise<void>;
11
+ remove?: (id: string) => Promise<void>;
12
+ changePriority?: (id: string, opts: {
13
+ priority: number;
14
+ lifo?: boolean;
15
+ }) => Promise<void>;
16
+ changeDelay?: (id: string, delay: number) => Promise<void>;
17
+ clearLogs?: (id: string, keepLogs?: number) => Promise<void>;
18
+ retry?: (id: string) => Promise<void>;
19
+ getState?: (id: string) => Promise<string>;
20
+ }
21
+ export interface FlowJobRuntime {
22
+ id: string;
23
+ queueName: string;
24
+ callbacks?: FlowJobCallbacks;
25
+ embedded: boolean;
26
+ tcp: TcpConnectionPool | null;
27
+ getState: () => Promise<JobStateType>;
28
+ }
29
+ export declare function assertFlowTcpOk(response: Record<string, unknown>, operation: string): void;