@taicode/common-base 1.7.2 → 1.7.4

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.
@@ -0,0 +1,655 @@
1
+ /**
2
+ * FlowQueue 流式队列处理器
3
+ *
4
+ * 一个支持异步处理、错误重试、延迟执行的队列管理工具,特别适用于以下场景:
5
+ *
6
+ * ## 使用场景
7
+ *
8
+ * ### 1. 复杂嵌套的解耦
9
+ * 当需要处理复杂的嵌套数据结构或多层依赖关系时,FlowQueue 可以帮助解耦处理逻辑:
10
+ *
11
+ * ```typescript
12
+ * // 示例:处理嵌套的文件目录结构
13
+ * interface FileNode {
14
+ * path: string;
15
+ * children?: FileNode[];
16
+ * }
17
+ *
18
+ * const queue = new FlowQueue<FileNode, ProcessedFile>(
19
+ * { delay: { base: 100 } }, // 避免过快处理导致资源竞争
20
+ * async (node) => {
21
+ * // 处理当前文件节点
22
+ * const result = await processFile(node.path);
23
+ *
24
+ * // 将子节点加入队列,实现解耦
25
+ * if (node.children) {
26
+ * queue.input(...node.children);
27
+ * }
28
+ *
29
+ * return result;
30
+ * }
31
+ * );
32
+ *
33
+ * // 开始处理根节点
34
+ * queue.input(rootNode);
35
+ * ```
36
+ *
37
+ * ### 2. 深度循环的解耦
38
+ * 在需要处理大量数据或深度递归时,FlowQueue 可以避免调用栈溢出和阻塞主线程:
39
+ *
40
+ * ```typescript
41
+ * // 示例:大数据集的分批处理
42
+ * interface DataChunk {
43
+ * data: any[];
44
+ * offset: number;
45
+ * total: number;
46
+ * }
47
+ *
48
+ * const queue = new FlowQueue<DataChunk, ProcessedChunk>(
49
+ * {
50
+ * delay: { base: 50, jitter: true }, // 避免连续处理导致的性能问题
51
+ * retry: { strategy: 'exponential', baseDelay: 1000, maxRetries: 3 }
52
+ * },
53
+ * async (chunk) => {
54
+ * const result = await processDataChunk(chunk.data);
55
+ *
56
+ * // 如果还有更多数据,继续加入队列
57
+ * if (chunk.offset + chunk.data.length < chunk.total) {
58
+ * const nextChunk = await loadNextChunk(chunk.offset + chunk.data.length);
59
+ * queue.input(nextChunk);
60
+ * }
61
+ *
62
+ * return result;
63
+ * }
64
+ * );
65
+ *
66
+ * // 监听处理进度
67
+ * queue.onGenerate((result) => {
68
+ * updateProgress(result);
69
+ * });
70
+ * ```
71
+ *
72
+ * ## 关键特性
73
+ * - **异步解耦**:通过队列机制避免深度递归和调用栈溢出
74
+ * - **错误重试**:支持多种重试策略,提高处理的可靠性
75
+ * - **流量控制**:可配置任务间延迟,避免资源竞争
76
+ * - **状态追踪**:清晰的成功/失败状态管理
77
+ * - **背压处理**:避免内存溢出的队列管理
78
+ * - **并发控制**:支持配置并发处理数量,默认为 1
79
+ * - **链式调用**:支持流畅的链式 API 调用
80
+ */
81
+ import { catchIt } from '../catch';
82
+ function delay(arg0) {
83
+ return new Promise(resolve => setTimeout(() => resolve(), arg0));
84
+ }
85
+ /**
86
+ * FlowQueue 流式队列处理器类
87
+ *
88
+ * 提供高效的异步队列处理能力,特别适用于需要解耦复杂嵌套结构和深度循环的场景。
89
+ *
90
+ * @template I 输入数据类型,继承自 FlowQueueInput
91
+ * @template O 输出数据类型,继承自 FlowQueueOutput
92
+ *
93
+ * @example
94
+ * ```typescript
95
+ * // 创建队列实例
96
+ * const queue = new FlowQueue<InputType, OutputType>(
97
+ * {
98
+ * retry: { strategy: 'exponential', baseDelay: 1000, maxRetries: 3 },
99
+ * delay: { base: 100, jitter: true },
100
+ * concurrency: 3 // 支持 3 个并发处理
101
+ * },
102
+ * async (input) => {
103
+ * // 处理逻辑
104
+ * return await processInput(input);
105
+ * }
106
+ * );
107
+ *
108
+ * // 传统方式
109
+ * queue.input(data1, data2, data3);
110
+ * queue.onGenerate(result => console.log('处理完成:', result));
111
+ * queue.closeInput();
112
+ * await queue.awaitCompletion();
113
+ *
114
+ * // 链式调用方式
115
+ * await queue
116
+ * .input(data1, data2)
117
+ * .input(data3)
118
+ * .closeInput()
119
+ * .awaitCompletion();
120
+ *
121
+ * // 重置并重新开始
122
+ * await queue
123
+ * .reset()
124
+ * .input(newData1, newData2)
125
+ * .closeInput()
126
+ * .awaitCompletion();
127
+ * ```
128
+ */
129
+ export class FlowQueue {
130
+ options;
131
+ processor;
132
+ pendingInputs = []; // 待处理
133
+ processedInputs = []; // 已处理
134
+ successOutputs = new Map();
135
+ erroredOutputs = new Map();
136
+ processingCount = 0; // 当前正在处理的任务数量
137
+ retryCount = new Map(); // 记录每个输入的重试次数
138
+ onGenerates = new Map();
139
+ isInputClosed = false; // 标记输入是否已关闭
140
+ completionPromise = null; // 完成状态的 Promise
141
+ completionResolve = null; // 完成状态的 resolve 函数
142
+ /**
143
+ * 创建 FlowQueue 实例
144
+ *
145
+ * @param options 队列配置选项
146
+ * @param processor 处理函数,接收输入并返回处理结果的 Promise
147
+ *
148
+ * processor 函数是解耦的核心:
149
+ * - 可以在处理过程中通过 this.input() 动态添加新任务
150
+ * - 支持异步处理,避免阻塞主线程
151
+ * - 失败时会根据重试策略自动重试
152
+ * - 支持并发处理,默认并发数为 1
153
+ *
154
+ * @example
155
+ * ```typescript
156
+ * // 处理嵌套文件结构的示例(单线程)
157
+ * const fileQueue = new FlowQueue<FileNode, ProcessedFile>(
158
+ * {
159
+ * retry: { strategy: 'exponential', baseDelay: 1000, maxRetries: 3 },
160
+ * delay: { base: 100, jitter: true },
161
+ * concurrency: 1 // 默认值,可省略
162
+ * },
163
+ * async (node) => {
164
+ * try {
165
+ * const result = await processFile(node.path);
166
+ *
167
+ * // 动态添加子节点,实现深度优先遍历的解耦
168
+ * if (node.children) {
169
+ * fileQueue.input(...node.children);
170
+ * }
171
+ *
172
+ * return result;
173
+ * } catch (error) {
174
+ * throw new Error(`处理文件 ${node.path} 失败: ${error.message}`);
175
+ * }
176
+ * }
177
+ * );
178
+ *
179
+ * // 并发处理示例
180
+ * const concurrentQueue = new FlowQueue<Task, Result>(
181
+ * {
182
+ * concurrency: 5, // 同时处理 5 个任务
183
+ * retry: { strategy: 'exponential', baseDelay: 1000, maxRetries: 3 }
184
+ * },
185
+ * async (task) => {
186
+ * return await processTask(task);
187
+ * }
188
+ * );
189
+ * ```
190
+ */
191
+ constructor(options, processor) {
192
+ this.options = options;
193
+ this.processor = processor;
194
+ // 设置重试配置默认值
195
+ this.options.retry = this.options.retry || { strategy: 'immediate' };
196
+ this.options.retry.maxRetries = this.options.retry.maxRetries ?? 3;
197
+ this.options.retry.jitter = this.options.retry.jitter ?? false;
198
+ // 设置任务间延迟配置默认值
199
+ this.options.delay = this.options.delay || {};
200
+ this.options.delay.base = this.options.delay.base ?? 0;
201
+ this.options.delay.jitter = this.options.delay.jitter ?? false;
202
+ this.options.delay.jitterRange = this.options.delay.jitterRange ?? 0.1;
203
+ // 设置并发配置默认值
204
+ this.options.concurrency = this.options.concurrency ?? 1;
205
+ }
206
+ /**
207
+ * 计算重试延迟时间
208
+ */
209
+ calculateRetryDelay(retryCount) {
210
+ const retryConfig = this.options.retry;
211
+ let delay = 0;
212
+ switch (retryConfig.strategy) {
213
+ case 'immediate':
214
+ case undefined:
215
+ delay = 0;
216
+ break;
217
+ case 'fixed':
218
+ delay = retryConfig.baseDelay;
219
+ if (retryConfig.maxDelay) {
220
+ delay = Math.min(delay, retryConfig.maxDelay);
221
+ }
222
+ break;
223
+ case 'exponential':
224
+ const multiplier = retryConfig.multiplier ?? 2;
225
+ delay = retryConfig.baseDelay * Math.pow(multiplier, retryCount);
226
+ if (retryConfig.maxDelay) {
227
+ delay = Math.min(delay, retryConfig.maxDelay);
228
+ }
229
+ break;
230
+ case 'linear':
231
+ delay = retryConfig.baseDelay * (retryCount + 1);
232
+ if (retryConfig.maxDelay) {
233
+ delay = Math.min(delay, retryConfig.maxDelay);
234
+ }
235
+ break;
236
+ case 'custom':
237
+ const baseDelay = retryConfig.baseDelay ?? 1000;
238
+ delay = retryConfig.customDelayFn(retryCount, baseDelay);
239
+ if (retryConfig.maxDelay) {
240
+ delay = Math.min(delay, retryConfig.maxDelay);
241
+ }
242
+ break;
243
+ default:
244
+ delay = 0;
245
+ }
246
+ // 添加随机抖动
247
+ if (retryConfig.jitter && delay > 0) {
248
+ const jitterRange = delay * 0.1; // 10% 的抖动范围
249
+ const jitter = (Math.random() - 0.5) * 2 * jitterRange;
250
+ delay = Math.max(0, delay + jitter);
251
+ }
252
+ return Math.floor(delay);
253
+ }
254
+ /**
255
+ * 计算任务间延迟时间
256
+ */
257
+ calculateTaskDelay() {
258
+ const delayConfig = this.options.delay;
259
+ let delay = delayConfig.base;
260
+ if (delayConfig.customDelayFn) {
261
+ delay = delayConfig.customDelayFn();
262
+ }
263
+ // 添加随机抖动
264
+ if (delayConfig.jitter && delay > 0) {
265
+ const jitterRange = delay * delayConfig.jitterRange;
266
+ const jitter = (Math.random() - 0.5) * 2 * jitterRange;
267
+ delay = Math.max(0, delay + jitter);
268
+ }
269
+ return Math.floor(delay);
270
+ }
271
+ /**
272
+ * 调度下一个处理任务
273
+ */
274
+ scheduleNextProcessing() {
275
+ // 启动尽可能多的处理任务,直到达到并发限制
276
+ const tasksToStart = Math.min(this.pendingInputs.length, this.options.concurrency - this.processingCount);
277
+ for (let i = 0; i < tasksToStart; i++) {
278
+ // 计算任务间延迟
279
+ const taskDelay = this.calculateTaskDelay();
280
+ if (taskDelay > 0) {
281
+ // 有延迟,使用 setTimeout
282
+ setTimeout(() => this.processFlow(), taskDelay);
283
+ }
284
+ else {
285
+ // 无延迟,使用 setTimeout(0) 避免调用栈过深
286
+ setTimeout(() => this.processFlow(), 0);
287
+ }
288
+ }
289
+ // 检查是否已标记为完成
290
+ this.checkAndTriggerCompletion();
291
+ }
292
+ /**
293
+ * 延迟执行重试
294
+ */
295
+ scheduleRetry(input, delayTime) {
296
+ this.pendingInputs.unshift(input);
297
+ if (delayTime <= 0) {
298
+ // 立即重试,启动调度
299
+ this.scheduleNextProcessing();
300
+ }
301
+ else {
302
+ // 延迟重试
303
+ setTimeout(() => {
304
+ this.scheduleNextProcessing();
305
+ }, delayTime);
306
+ }
307
+ }
308
+ /**
309
+ * 检查是否已完成并触发完成回调
310
+ */
311
+ async checkAndTriggerCompletion() {
312
+ await delay(0); // 确保在当前执行栈完成后再检查
313
+ if (this.isInputClosed && this.pendingInputs.length === 0 && this.processingCount === 0 && this.completionResolve) {
314
+ this.completionResolve();
315
+ this.completionResolve = null;
316
+ }
317
+ }
318
+ /**
319
+ * 检查当前的待处理队列,取出一个进行处理
320
+ * 处理完成后更新 output 并将输入移动到 processedInputs
321
+ * 当 processor 处理失败时,将错误信息存入 output(FlowError)
322
+ * 可以设置失败的重试次数,如果超过最大重试次数则不再重试
323
+ */
324
+ async processFlow() {
325
+ // 检查并发限制
326
+ if (this.processingCount >= this.options.concurrency) {
327
+ return;
328
+ }
329
+ // 取出第一个待处理的输入
330
+ const input = this.pendingInputs.shift();
331
+ if (!input) {
332
+ this.checkAndTriggerCompletion();
333
+ return;
334
+ }
335
+ // 增加处理计数
336
+ this.processingCount++;
337
+ try {
338
+ // 获取当前输入的重试次数
339
+ const currentRetries = this.retryCount.get(input) || 0;
340
+ // 使用 processor 处理输入
341
+ const result = await catchIt(() => this.processor(input));
342
+ if (result.isError()) {
343
+ if (currentRetries < this.options.retry.maxRetries) {
344
+ // 还可以重试,增加重试次数并计算延迟
345
+ this.retryCount.set(input, currentRetries + 1);
346
+ const delay = this.calculateRetryDelay(currentRetries);
347
+ this.scheduleRetry(input, delay);
348
+ }
349
+ else {
350
+ // 超过最大重试次数,记录错误并移动到已处理
351
+ this.erroredOutputs.set(input, result.error);
352
+ this.processedInputs.push(input);
353
+ this.retryCount.delete(input);
354
+ }
355
+ }
356
+ else {
357
+ // 处理成功,存储结果
358
+ this.successOutputs.set(input, result.value);
359
+ this.processedInputs.push(input);
360
+ this.retryCount.delete(input);
361
+ // 清除可能存在的错误记录
362
+ this.erroredOutputs.delete(input);
363
+ // 通知所有注册的回调
364
+ await this.notifyOnGenerates(result.value);
365
+ }
366
+ }
367
+ catch (error) {
368
+ console.error('Error in processFlow:', error);
369
+ }
370
+ finally {
371
+ // 减少正在处理的任务计数
372
+ this.processingCount--;
373
+ // 处理完当前输入后,尝试启动更多处理任务
374
+ this.scheduleNextProcessing();
375
+ }
376
+ }
377
+ /**
378
+ * 通知所有注册的回调函数
379
+ */
380
+ async notifyOnGenerates(output) {
381
+ for (const callback of this.onGenerates.values()) {
382
+ const result = await catchIt(() => callback(output));
383
+ if (result.isError()) {
384
+ console.error('Error in onGenerate callback:', result.error);
385
+ }
386
+ }
387
+ }
388
+ /**
389
+ * 向队列添加输入数据
390
+ *
391
+ * 此方法是解耦复杂嵌套结构的关键:
392
+ * - 在 processor 函数内部可以动态添加新的输入
393
+ * - 避免了深度递归调用栈
394
+ * - 支持批量添加多个输入
395
+ * - 支持链式调用
396
+ *
397
+ * @param inputs 要处理的输入数据
398
+ * @returns 返回 FlowQueue 实例以支持链式调用
399
+ *
400
+ * @example
401
+ * ```typescript
402
+ * // 在处理器中动态添加子任务
403
+ * const processor = async (node: TreeNode) => {
404
+ * const result = await processNode(node);
405
+ *
406
+ * // 将子节点加入队列,实现解耦
407
+ * if (node.children) {
408
+ * queue.input(...node.children);
409
+ * }
410
+ *
411
+ * return result;
412
+ * };
413
+ *
414
+ * // 链式调用示例
415
+ * queue
416
+ * .input(data1, data2)
417
+ * .input(data3)
418
+ * .closeInput();
419
+ * ```
420
+ */
421
+ input(...inputs) {
422
+ if (this.isInputClosed)
423
+ return this;
424
+ this.pendingInputs.push(...inputs);
425
+ this.processFlow();
426
+ return this;
427
+ }
428
+ /**
429
+ * 注册输出监听器
430
+ *
431
+ * 用于监听每个成功处理的输出,适用于:
432
+ * - 实时更新处理进度
433
+ * - 流式处理大数据集
434
+ * - 实现观察者模式解耦
435
+ *
436
+ * @param callback 当有新输出时调用的回调函数
437
+ * @returns 取消监听的函数
438
+ *
439
+ * @example
440
+ * ```typescript
441
+ * // 监听处理进度
442
+ * const unsubscribe = queue.onGenerate((result) => {
443
+ * updateProgressBar(result);
444
+ * saveToDatabase(result);
445
+ * });
446
+ *
447
+ * // 在适当时机取消监听
448
+ * unsubscribe();
449
+ * ```
450
+ */
451
+ onGenerate(callback) {
452
+ const id = Math.random().toString(36);
453
+ this.onGenerates.set(id, callback);
454
+ return () => this.onGenerates.delete(id);
455
+ }
456
+ /**
457
+ * 只读标记,代表是否当前已经 closeInput 并且所有输入都已经处理完毕
458
+ */
459
+ get isCompleted() {
460
+ return this.isInputClosed && this.pendingInputs.length === 0 && this.processingCount === 0;
461
+ }
462
+ /**
463
+ * 标记当前 FlowQueue 不会再有新的输入了
464
+ *
465
+ * 调用此方法后:
466
+ * - 队列将不再接受新的输入
467
+ * - 当所有现有输入处理完成后,队列将进入完成状态
468
+ * - 可以通过 awaitCompletion() 等待所有处理完成
469
+ * - 支持链式调用
470
+ *
471
+ * 在深度循环解耦场景中,这是控制处理边界的重要方法。
472
+ *
473
+ * @returns 返回 FlowQueue 实例以支持链式调用
474
+ *
475
+ * @example
476
+ * ```typescript
477
+ * // 添加所有初始数据
478
+ * queue.input(...initialData);
479
+ *
480
+ * // 标记输入结束
481
+ * queue.closeInput();
482
+ *
483
+ * // 等待所有处理完成
484
+ * await queue.awaitCompletion();
485
+ * console.log('所有数据处理完成');
486
+ *
487
+ * // 链式调用示例
488
+ * await queue
489
+ * .input(data1, data2)
490
+ * .closeInput()
491
+ * .awaitCompletion();
492
+ * ```
493
+ */
494
+ closeInput() {
495
+ this.isInputClosed = true;
496
+ // 使用统一的完成检查方法
497
+ this.checkAndTriggerCompletion();
498
+ return this;
499
+ }
500
+ /**
501
+ * 返回一个 Promise,代表当前已经标记为输入关闭状态、所有输入都已经处理完毕
502
+ *
503
+ * 这是等待所有异步处理完成的最佳方式,特别适用于:
504
+ * - 等待深度循环处理完成
505
+ * - 确保所有嵌套任务都已处理
506
+ * - 在测试中等待异步操作完成
507
+ *
508
+ * @returns Promise,在所有输入处理完成时 resolve
509
+ *
510
+ * @example
511
+ * ```typescript
512
+ * // 处理大量嵌套数据
513
+ * queue.input(rootData);
514
+ * queue.closeInput();
515
+ *
516
+ * // 等待所有嵌套处理完成
517
+ * await queue.awaitCompletion();
518
+ *
519
+ * // 检查处理结果
520
+ * console.log('成功处理:', queue.successOutputs.size);
521
+ * console.log('处理失败:', queue.erroredOutputs.size);
522
+ * ```
523
+ */
524
+ awaitCompletion() {
525
+ if (this.completionPromise) {
526
+ return this.completionPromise;
527
+ }
528
+ // 如果已经标记为输入关闭且没有待处理的输入和正在处理的任务,立即返回 resolved Promise
529
+ if (this.isInputClosed && this.pendingInputs.length === 0 && this.processingCount === 0) {
530
+ console.log('所有输入已处理完毕');
531
+ return Promise.resolve();
532
+ }
533
+ // 创建新的 Promise
534
+ this.completionPromise = new Promise((resolve) => {
535
+ this.completionResolve = () => {
536
+ console.log('所有输入已处理完毕');
537
+ resolve();
538
+ };
539
+ });
540
+ return this.completionPromise;
541
+ }
542
+ /**
543
+ * 移除尚未处理的输入并调用 closeInput
544
+ *
545
+ * @returns 返回 FlowQueue 实例以支持链式调用
546
+ *
547
+ * @example
548
+ * ```typescript
549
+ * // 链式调用示例
550
+ * queue
551
+ * .input(data1, data2)
552
+ * .cancel()
553
+ * .reset();
554
+ * ```
555
+ */
556
+ cancel() {
557
+ // 清除所有待处理的输入
558
+ this.pendingInputs.length = 0;
559
+ // 清除重试计数
560
+ this.retryCount.clear();
561
+ // 标记输入已关闭
562
+ this.closeInput();
563
+ return this;
564
+ }
565
+ /**
566
+ * 重置 FlowQueue 到初始状态
567
+ * 清空所有数据,包括待处理、已处理、输出、重试计数等
568
+ * 重置后可以重新开始处理
569
+ *
570
+ * @returns 返回 FlowQueue 实例以支持链式调用
571
+ *
572
+ * @example
573
+ * ```typescript
574
+ * // 链式调用示例
575
+ * queue
576
+ * .reset()
577
+ * .input(newData1, newData2)
578
+ * .closeInput();
579
+ * ```
580
+ */
581
+ reset() {
582
+ // 清空所有队列和状态
583
+ this.successOutputs.clear();
584
+ this.erroredOutputs.clear();
585
+ this.retryCount.clear();
586
+ this.pendingInputs.length = 0;
587
+ this.processedInputs.length = 0;
588
+ // 重置处理状态
589
+ this.processingCount = 0;
590
+ this.isInputClosed = false;
591
+ // 重置完成状态
592
+ if (this.completionResolve) {
593
+ this.completionResolve();
594
+ this.completionResolve = null;
595
+ }
596
+ this.completionPromise = null;
597
+ return this;
598
+ }
599
+ /**
600
+ * 重试所有失败的输入
601
+ *
602
+ * 自动将所有失败的输入从已处理队列移回待处理队列,并启动处理。
603
+ * 在处理复杂嵌套结构时,某些节点可能因为依赖关系而暂时失败,
604
+ * 此方法可以在依赖解决后重新处理这些失败的节点。
605
+ *
606
+ * @returns 被移动到待处理队列的输入数量
607
+ *
608
+ * @example
609
+ * ```typescript
610
+ * // 第一轮处理
611
+ * queue.input(...allData);
612
+ * queue.closeInput();
613
+ * await queue.awaitCompletion();
614
+ *
615
+ * // 检查是否有失败的项
616
+ * if (queue.erroredOutputs.size > 0) {
617
+ * console.log(`有 ${queue.erroredOutputs.size} 个项目处理失败`);
618
+ *
619
+ * // 重试失败的项目
620
+ * const retryCount = queue.retry();
621
+ * console.log(`重试 ${retryCount} 个项目`);
622
+ *
623
+ * // 等待重试完成
624
+ * await queue.awaitCompletion();
625
+ * }
626
+ * ```
627
+ */
628
+ retry() {
629
+ // 直接从 erroredOutputs Map 中获取所有失败的输入
630
+ const retryInputs = Array.from(this.erroredOutputs.keys());
631
+ if (retryInputs.length > 0) {
632
+ // 从已处理队列中移除这些输入
633
+ for (const input of retryInputs) {
634
+ const index = this.processedInputs.indexOf(input);
635
+ if (index > -1) {
636
+ this.processedInputs.splice(index, 1);
637
+ }
638
+ }
639
+ // 清除错误记录和重试计数
640
+ this.erroredOutputs.clear();
641
+ for (const input of retryInputs) {
642
+ this.retryCount.delete(input);
643
+ }
644
+ // 将要重试的输入添加到待处理队列的前面(优先处理)
645
+ this.pendingInputs.unshift(...retryInputs);
646
+ // 启动处理(保持输入关闭状态,仅重试现有错误)
647
+ this.processFlow();
648
+ }
649
+ else {
650
+ // 没有失败的输入需要重试,检查是否应该触发完成状态
651
+ this.checkAndTriggerCompletion();
652
+ }
653
+ return retryInputs.length;
654
+ }
655
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=flow-queue.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flow-queue.test.d.ts","sourceRoot":"","sources":["../../source/flow-queue/flow-queue.test.ts"],"names":[],"mappings":""}