@aws-sdk/lib-sqs 3.1158.0 → 3.1159.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.
- package/dist-cjs/index.js +92 -46
- package/dist-es/Message.js +2 -1
- package/dist-es/SQSPoller.js +90 -45
- package/package.json +3 -3
package/dist-cjs/index.js
CHANGED
|
@@ -24,8 +24,9 @@ class Message {
|
|
|
24
24
|
return this._handled;
|
|
25
25
|
}
|
|
26
26
|
enqueueDelete() {
|
|
27
|
-
if (this._handled)
|
|
27
|
+
if (this._handled) {
|
|
28
28
|
return;
|
|
29
|
+
}
|
|
29
30
|
this._handled = true;
|
|
30
31
|
this._callbacks.enqueueDelete(this);
|
|
31
32
|
}
|
|
@@ -142,26 +143,33 @@ class SQSPoller {
|
|
|
142
143
|
heartbeatExpired: [],
|
|
143
144
|
};
|
|
144
145
|
constructor(config) {
|
|
145
|
-
if (!config.queueUrl)
|
|
146
|
+
if (!config.queueUrl) {
|
|
146
147
|
throw new PollerError("queueUrl is required");
|
|
148
|
+
}
|
|
147
149
|
this._client = config.client ?? new SQSClient(config.clientConfig ?? {});
|
|
148
150
|
const batchSize = config.receiveBatchSize ?? DEFAULTS.receiveBatchSize;
|
|
149
|
-
if (batchSize < 1 || batchSize > 10 || !Number.isInteger(batchSize))
|
|
151
|
+
if (batchSize < 1 || batchSize > 10 || !Number.isInteger(batchSize)) {
|
|
150
152
|
throw new PollerError("receiveBatchSize must be an integer between 1 and 10");
|
|
153
|
+
}
|
|
151
154
|
const deleteBatchSize = config.deleteBatchSize ?? DEFAULTS.deleteBatchSize;
|
|
152
|
-
if (deleteBatchSize < 1 || deleteBatchSize > 10 || !Number.isInteger(deleteBatchSize))
|
|
155
|
+
if (deleteBatchSize < 1 || deleteBatchSize > 10 || !Number.isInteger(deleteBatchSize)) {
|
|
153
156
|
throw new PollerError("deleteBatchSize must be an integer between 1 and 10");
|
|
157
|
+
}
|
|
154
158
|
const receiveWaitTimeMs = config.receiveWaitTimeMs ?? DEFAULTS.receiveWaitTimeMs;
|
|
155
|
-
if (receiveWaitTimeMs < 0 || receiveWaitTimeMs > 20_000)
|
|
159
|
+
if (receiveWaitTimeMs < 0 || receiveWaitTimeMs > 20_000) {
|
|
156
160
|
throw new PollerError("receiveWaitTimeMs must be between 0 and 20000");
|
|
161
|
+
}
|
|
157
162
|
const maxConcurrency = config.maxConcurrency ?? DEFAULTS.maxConcurrency;
|
|
158
|
-
if (!Number.isInteger(maxConcurrency) || maxConcurrency < 1)
|
|
163
|
+
if (!Number.isInteger(maxConcurrency) || maxConcurrency < 1) {
|
|
159
164
|
throw new PollerError("maxConcurrency must be a positive integer");
|
|
165
|
+
}
|
|
160
166
|
if (config.extendTimeout) {
|
|
161
|
-
if (config.visibilityTimeoutMs == null)
|
|
167
|
+
if (config.visibilityTimeoutMs == null) {
|
|
162
168
|
throw new PollerError("visibilityTimeoutMs is required when extendTimeout is true");
|
|
163
|
-
|
|
169
|
+
}
|
|
170
|
+
if ((config.extendTimeoutAdvanceMs ?? DEFAULTS.extendTimeoutAdvanceMs) >= config.visibilityTimeoutMs) {
|
|
164
171
|
throw new PollerError("extendTimeoutAdvanceMs must be less than visibilityTimeoutMs");
|
|
172
|
+
}
|
|
165
173
|
}
|
|
166
174
|
this._config = {
|
|
167
175
|
queueUrl: config.queueUrl,
|
|
@@ -232,8 +240,9 @@ class SQSPoller {
|
|
|
232
240
|
}
|
|
233
241
|
const arr = this._listeners[event];
|
|
234
242
|
const idx = arr.indexOf(listener);
|
|
235
|
-
if (idx !== -1)
|
|
243
|
+
if (idx !== -1) {
|
|
236
244
|
arr.splice(idx, 1);
|
|
245
|
+
}
|
|
237
246
|
return this;
|
|
238
247
|
}
|
|
239
248
|
start() {
|
|
@@ -244,8 +253,9 @@ class SQSPoller {
|
|
|
244
253
|
}
|
|
245
254
|
async stop(graceful = true) {
|
|
246
255
|
const run = this._run;
|
|
247
|
-
if (!run)
|
|
256
|
+
if (!run) {
|
|
248
257
|
return { ...this._stats };
|
|
258
|
+
}
|
|
249
259
|
run.stopping = true;
|
|
250
260
|
run.ac.abort();
|
|
251
261
|
if (!graceful) {
|
|
@@ -254,10 +264,12 @@ class SQSPoller {
|
|
|
254
264
|
}
|
|
255
265
|
if (run.iterator) {
|
|
256
266
|
const outcome = run.graceful ? await this._waitFor(run.done, run) : "hard";
|
|
257
|
-
if (outcome === "timeout")
|
|
267
|
+
if (outcome === "timeout") {
|
|
258
268
|
this._emitShutdownTimeout("the async iterator was not advanced");
|
|
259
|
-
|
|
269
|
+
}
|
|
270
|
+
if (outcome !== "done") {
|
|
260
271
|
await run.iterator.return(undefined);
|
|
272
|
+
}
|
|
261
273
|
}
|
|
262
274
|
await run.done;
|
|
263
275
|
return { ...this._stats };
|
|
@@ -277,36 +289,43 @@ class SQSPoller {
|
|
|
277
289
|
while (!run.stopping && !this._isAborted(run)) {
|
|
278
290
|
let batch = [];
|
|
279
291
|
try {
|
|
280
|
-
if (!(await this._runBeforeRequest(run)))
|
|
292
|
+
if (!(await this._runBeforeRequest(run))) {
|
|
281
293
|
break;
|
|
294
|
+
}
|
|
282
295
|
const messages = await this._receiveMessages(run);
|
|
283
296
|
run.consecutiveErrors = 0;
|
|
284
297
|
if (messages.length === 0) {
|
|
285
|
-
if (await this._handleEmpty(run))
|
|
298
|
+
if (await this._handleEmpty(run)) {
|
|
286
299
|
break;
|
|
300
|
+
}
|
|
287
301
|
continue;
|
|
288
302
|
}
|
|
289
303
|
this._recordReceived(messages.length);
|
|
290
304
|
batch = messages.map((raw) => this._wrapMessage(raw, run));
|
|
291
|
-
for (const msg of batch)
|
|
305
|
+
for (const msg of batch) {
|
|
292
306
|
this._startHeartbeat(msg, run);
|
|
307
|
+
}
|
|
293
308
|
}
|
|
294
309
|
catch (err) {
|
|
295
|
-
if (this._isAborted(run))
|
|
310
|
+
if (this._isAborted(run)) {
|
|
296
311
|
break;
|
|
312
|
+
}
|
|
297
313
|
await this._handlePollError(err, run);
|
|
298
314
|
continue;
|
|
299
315
|
}
|
|
300
316
|
for (const msg of batch) {
|
|
301
|
-
if (run.stopping || this._isAborted(run))
|
|
317
|
+
if (run.stopping || this._isAborted(run)) {
|
|
302
318
|
break;
|
|
319
|
+
}
|
|
303
320
|
yield msg;
|
|
304
321
|
void this._stopHeartbeat(msg.receiptHandle, run);
|
|
305
|
-
if (this._config.deleteMessages && !msg.handled)
|
|
322
|
+
if (this._config.deleteMessages && !msg.handled) {
|
|
306
323
|
msg.enqueueDelete();
|
|
324
|
+
}
|
|
307
325
|
}
|
|
308
|
-
if (this._config.activePollIntervalMs > 0)
|
|
326
|
+
if (this._config.activePollIntervalMs > 0) {
|
|
309
327
|
await this._delay(this._config.activePollIntervalMs, run);
|
|
328
|
+
}
|
|
310
329
|
}
|
|
311
330
|
}
|
|
312
331
|
finally {
|
|
@@ -314,14 +333,17 @@ class SQSPoller {
|
|
|
314
333
|
}
|
|
315
334
|
}
|
|
316
335
|
_assertCanStart(activeMessage) {
|
|
317
|
-
if (this._run && !this._run.stopping)
|
|
336
|
+
if (this._run && !this._run.stopping) {
|
|
318
337
|
throw new PollerError(activeMessage);
|
|
319
|
-
|
|
338
|
+
}
|
|
339
|
+
if (this._externalSignal?.aborted) {
|
|
320
340
|
throw new PollerError("abortSignal is already aborted");
|
|
341
|
+
}
|
|
321
342
|
}
|
|
322
343
|
async _beginRun(run) {
|
|
323
|
-
if (run.previous)
|
|
344
|
+
if (run.previous) {
|
|
324
345
|
await run.previous;
|
|
346
|
+
}
|
|
325
347
|
this._stats.pollingStartedAt = new Date();
|
|
326
348
|
this._stats.pollingStoppedAt = null;
|
|
327
349
|
}
|
|
@@ -334,8 +356,9 @@ class SQSPoller {
|
|
|
334
356
|
run.stopping = true;
|
|
335
357
|
run.finished = true;
|
|
336
358
|
this._stats.pollingStoppedAt = new Date();
|
|
337
|
-
if (this._run === run)
|
|
359
|
+
if (this._run === run) {
|
|
338
360
|
this._run = null;
|
|
361
|
+
}
|
|
339
362
|
run.resolveDone();
|
|
340
363
|
this._emit("stopped", { ...this._stats });
|
|
341
364
|
}
|
|
@@ -360,8 +383,9 @@ class SQSPoller {
|
|
|
360
383
|
});
|
|
361
384
|
}
|
|
362
385
|
async _waitForDrain(run) {
|
|
363
|
-
if (run.inFlight === 0)
|
|
386
|
+
if (run.inFlight === 0) {
|
|
364
387
|
return;
|
|
388
|
+
}
|
|
365
389
|
const drained = new Promise((resolve) => run.drainResolvers.push(resolve));
|
|
366
390
|
if ((await this._waitFor(drained, run)) === "timeout") {
|
|
367
391
|
this._emitShutdownTimeout(`${run.inFlight} message(s) were still in flight`);
|
|
@@ -375,17 +399,21 @@ class SQSPoller {
|
|
|
375
399
|
await this._beginRun(run);
|
|
376
400
|
while (!run.stopping && !this._isAborted(run)) {
|
|
377
401
|
try {
|
|
378
|
-
while (!run.stopping && run.inFlight >= this._config.maxConcurrency)
|
|
402
|
+
while (!run.stopping && run.inFlight >= this._config.maxConcurrency) {
|
|
379
403
|
await this._delay(50, run);
|
|
380
|
-
|
|
404
|
+
}
|
|
405
|
+
if (run.stopping || this._isAborted(run)) {
|
|
381
406
|
break;
|
|
382
|
-
|
|
407
|
+
}
|
|
408
|
+
if (!(await this._runBeforeRequest(run))) {
|
|
383
409
|
break;
|
|
410
|
+
}
|
|
384
411
|
const messages = await this._receiveMessages(run, Math.min(this._config.receiveBatchSize, this._config.maxConcurrency - run.inFlight));
|
|
385
412
|
run.consecutiveErrors = 0;
|
|
386
413
|
if (messages.length === 0) {
|
|
387
|
-
if (await this._handleEmpty(run))
|
|
414
|
+
if (await this._handleEmpty(run)) {
|
|
388
415
|
break;
|
|
416
|
+
}
|
|
389
417
|
continue;
|
|
390
418
|
}
|
|
391
419
|
this._recordReceived(messages.length);
|
|
@@ -395,33 +423,39 @@ class SQSPoller {
|
|
|
395
423
|
void this._processMessage(msg, run).finally(() => {
|
|
396
424
|
run.inFlight--;
|
|
397
425
|
if (run.inFlight === 0) {
|
|
398
|
-
for (const resolve of run.drainResolvers)
|
|
426
|
+
for (const resolve of run.drainResolvers) {
|
|
399
427
|
resolve();
|
|
428
|
+
}
|
|
400
429
|
run.drainResolvers = [];
|
|
401
430
|
}
|
|
402
431
|
});
|
|
403
432
|
}
|
|
404
|
-
if (this._config.activePollIntervalMs > 0)
|
|
433
|
+
if (this._config.activePollIntervalMs > 0) {
|
|
405
434
|
await this._delay(this._config.activePollIntervalMs, run);
|
|
435
|
+
}
|
|
406
436
|
}
|
|
407
437
|
catch (err) {
|
|
408
|
-
if (this._isAborted(run))
|
|
438
|
+
if (this._isAborted(run)) {
|
|
409
439
|
break;
|
|
440
|
+
}
|
|
410
441
|
await this._handlePollError(err, run);
|
|
411
442
|
}
|
|
412
443
|
}
|
|
413
|
-
if (run.graceful)
|
|
444
|
+
if (run.graceful) {
|
|
414
445
|
await this._waitForDrain(run);
|
|
446
|
+
}
|
|
415
447
|
await this._teardown(run);
|
|
416
448
|
}
|
|
417
449
|
async _processMessage(msg, run) {
|
|
418
450
|
this._startHeartbeat(msg, run);
|
|
419
451
|
try {
|
|
420
452
|
const hasListeners = this._listeners.message.length > 0;
|
|
421
|
-
if (hasListeners)
|
|
453
|
+
if (hasListeners) {
|
|
422
454
|
await this._emitAsync("message", msg);
|
|
423
|
-
|
|
455
|
+
}
|
|
456
|
+
if (this._config.deleteMessages && !msg.handled && hasListeners) {
|
|
424
457
|
msg.enqueueDelete();
|
|
458
|
+
}
|
|
425
459
|
}
|
|
426
460
|
catch (err) {
|
|
427
461
|
this._stats.errorCount++;
|
|
@@ -432,8 +466,9 @@ class SQSPoller {
|
|
|
432
466
|
}
|
|
433
467
|
}
|
|
434
468
|
async _runBeforeRequest(run) {
|
|
435
|
-
if (!this._config.beforeRequest)
|
|
469
|
+
if (!this._config.beforeRequest) {
|
|
436
470
|
return true;
|
|
471
|
+
}
|
|
437
472
|
try {
|
|
438
473
|
await this._config.beforeRequest(this.getStats());
|
|
439
474
|
return true;
|
|
@@ -452,8 +487,9 @@ class SQSPoller {
|
|
|
452
487
|
return true;
|
|
453
488
|
}
|
|
454
489
|
const delayMs = this._effectiveIdlePollInterval();
|
|
455
|
-
if (delayMs > 0)
|
|
490
|
+
if (delayMs > 0) {
|
|
456
491
|
await this._delay(delayMs, run);
|
|
492
|
+
}
|
|
457
493
|
return false;
|
|
458
494
|
}
|
|
459
495
|
async _handlePollError(err, run) {
|
|
@@ -495,8 +531,9 @@ class SQSPoller {
|
|
|
495
531
|
clearTimeout(this._deleteTimer);
|
|
496
532
|
this._deleteTimer = null;
|
|
497
533
|
}
|
|
498
|
-
if (this._deleteBatch.length === 0)
|
|
534
|
+
if (this._deleteBatch.length === 0) {
|
|
499
535
|
return;
|
|
536
|
+
}
|
|
500
537
|
const batch = this._deleteBatch.splice(0, this._config.deleteBatchSize);
|
|
501
538
|
const idMap = new Map();
|
|
502
539
|
const entries = batch.map((m, i) => {
|
|
@@ -517,27 +554,32 @@ class SQSPoller {
|
|
|
517
554
|
this._stats.errorCount++;
|
|
518
555
|
this._emit("error", err instanceof Error ? err : new PollerError(String(err)));
|
|
519
556
|
}
|
|
520
|
-
if (this._deleteBatch.length > 0)
|
|
557
|
+
if (this._deleteBatch.length > 0) {
|
|
521
558
|
await this._flushDeleteBatch();
|
|
559
|
+
}
|
|
522
560
|
}
|
|
523
561
|
_trackFlush(p) {
|
|
524
562
|
this._pendingFlushes.push(p);
|
|
525
563
|
p.finally(() => {
|
|
526
564
|
const i = this._pendingFlushes.indexOf(p);
|
|
527
|
-
if (i !== -1)
|
|
565
|
+
if (i !== -1) {
|
|
528
566
|
this._pendingFlushes.splice(i, 1);
|
|
567
|
+
}
|
|
529
568
|
});
|
|
530
569
|
}
|
|
531
570
|
async _awaitPendingFlushes() {
|
|
532
|
-
while (this._pendingFlushes.length > 0)
|
|
571
|
+
while (this._pendingFlushes.length > 0) {
|
|
533
572
|
await Promise.all([...this._pendingFlushes]);
|
|
573
|
+
}
|
|
534
574
|
}
|
|
535
575
|
_startHeartbeat(msg, run) {
|
|
536
|
-
if (!this._config.extendTimeout || this._config.visibilityTimeoutMs == null)
|
|
576
|
+
if (!this._config.extendTimeout || this._config.visibilityTimeoutMs == null) {
|
|
537
577
|
return;
|
|
578
|
+
}
|
|
538
579
|
const intervalMs = this._config.visibilityTimeoutMs - this._config.extendTimeoutAdvanceMs;
|
|
539
|
-
if (intervalMs <= 0)
|
|
580
|
+
if (intervalMs <= 0) {
|
|
540
581
|
return;
|
|
582
|
+
}
|
|
541
583
|
run.receiptHandles.add(msg.receiptHandle);
|
|
542
584
|
const startTime = Date.now();
|
|
543
585
|
const scheduleNext = () => {
|
|
@@ -567,8 +609,9 @@ class SQSPoller {
|
|
|
567
609
|
finally {
|
|
568
610
|
this._heartbeatsInFlight.delete(msg.receiptHandle);
|
|
569
611
|
}
|
|
570
|
-
if (this._heartbeatTimers.has(msg.receiptHandle))
|
|
612
|
+
if (this._heartbeatTimers.has(msg.receiptHandle)) {
|
|
571
613
|
scheduleNext();
|
|
614
|
+
}
|
|
572
615
|
}, intervalMs);
|
|
573
616
|
this._heartbeatTimers.set(msg.receiptHandle, timer);
|
|
574
617
|
};
|
|
@@ -611,16 +654,18 @@ class SQSPoller {
|
|
|
611
654
|
return run.ac.signal.aborted || this._externalSignal?.aborted === true;
|
|
612
655
|
}
|
|
613
656
|
_checkIdleTimeout() {
|
|
614
|
-
if (this._config.idleTimeoutMs == null)
|
|
657
|
+
if (this._config.idleTimeoutMs == null) {
|
|
615
658
|
return false;
|
|
659
|
+
}
|
|
616
660
|
const started = this._stats.pollingStartedAt?.getTime() ?? 0;
|
|
617
661
|
const lastMessage = this._stats.lastMessageReceivedAt?.getTime() ?? 0;
|
|
618
662
|
const since = Math.max(started, lastMessage);
|
|
619
663
|
return since > 0 && Date.now() - since > this._config.idleTimeoutMs;
|
|
620
664
|
}
|
|
621
665
|
_effectiveIdlePollInterval() {
|
|
622
|
-
if (this._config.idlePollIntervalMs > 0)
|
|
666
|
+
if (this._config.idlePollIntervalMs > 0) {
|
|
623
667
|
return this._config.idlePollIntervalMs;
|
|
668
|
+
}
|
|
624
669
|
return this._config.receiveWaitTimeMs === 0 ? MIN_POLL_INTERVAL_MS : 0;
|
|
625
670
|
}
|
|
626
671
|
async _backoff(run) {
|
|
@@ -653,8 +698,9 @@ class SQSPoller {
|
|
|
653
698
|
}
|
|
654
699
|
}
|
|
655
700
|
async _emitAsync(event, ...args) {
|
|
656
|
-
for (const fn of this._listeners[event])
|
|
701
|
+
for (const fn of this._listeners[event]) {
|
|
657
702
|
await fn(...args);
|
|
703
|
+
}
|
|
658
704
|
}
|
|
659
705
|
}
|
|
660
706
|
|
package/dist-es/Message.js
CHANGED
package/dist-es/SQSPoller.js
CHANGED
|
@@ -68,26 +68,33 @@ export class SQSPoller {
|
|
|
68
68
|
heartbeatExpired: [],
|
|
69
69
|
};
|
|
70
70
|
constructor(config) {
|
|
71
|
-
if (!config.queueUrl)
|
|
71
|
+
if (!config.queueUrl) {
|
|
72
72
|
throw new PollerError("queueUrl is required");
|
|
73
|
+
}
|
|
73
74
|
this._client = config.client ?? new SQSClient(config.clientConfig ?? {});
|
|
74
75
|
const batchSize = config.receiveBatchSize ?? DEFAULTS.receiveBatchSize;
|
|
75
|
-
if (batchSize < 1 || batchSize > 10 || !Number.isInteger(batchSize))
|
|
76
|
+
if (batchSize < 1 || batchSize > 10 || !Number.isInteger(batchSize)) {
|
|
76
77
|
throw new PollerError("receiveBatchSize must be an integer between 1 and 10");
|
|
78
|
+
}
|
|
77
79
|
const deleteBatchSize = config.deleteBatchSize ?? DEFAULTS.deleteBatchSize;
|
|
78
|
-
if (deleteBatchSize < 1 || deleteBatchSize > 10 || !Number.isInteger(deleteBatchSize))
|
|
80
|
+
if (deleteBatchSize < 1 || deleteBatchSize > 10 || !Number.isInteger(deleteBatchSize)) {
|
|
79
81
|
throw new PollerError("deleteBatchSize must be an integer between 1 and 10");
|
|
82
|
+
}
|
|
80
83
|
const receiveWaitTimeMs = config.receiveWaitTimeMs ?? DEFAULTS.receiveWaitTimeMs;
|
|
81
|
-
if (receiveWaitTimeMs < 0 || receiveWaitTimeMs > 20_000)
|
|
84
|
+
if (receiveWaitTimeMs < 0 || receiveWaitTimeMs > 20_000) {
|
|
82
85
|
throw new PollerError("receiveWaitTimeMs must be between 0 and 20000");
|
|
86
|
+
}
|
|
83
87
|
const maxConcurrency = config.maxConcurrency ?? DEFAULTS.maxConcurrency;
|
|
84
|
-
if (!Number.isInteger(maxConcurrency) || maxConcurrency < 1)
|
|
88
|
+
if (!Number.isInteger(maxConcurrency) || maxConcurrency < 1) {
|
|
85
89
|
throw new PollerError("maxConcurrency must be a positive integer");
|
|
90
|
+
}
|
|
86
91
|
if (config.extendTimeout) {
|
|
87
|
-
if (config.visibilityTimeoutMs == null)
|
|
92
|
+
if (config.visibilityTimeoutMs == null) {
|
|
88
93
|
throw new PollerError("visibilityTimeoutMs is required when extendTimeout is true");
|
|
89
|
-
|
|
94
|
+
}
|
|
95
|
+
if ((config.extendTimeoutAdvanceMs ?? DEFAULTS.extendTimeoutAdvanceMs) >= config.visibilityTimeoutMs) {
|
|
90
96
|
throw new PollerError("extendTimeoutAdvanceMs must be less than visibilityTimeoutMs");
|
|
97
|
+
}
|
|
91
98
|
}
|
|
92
99
|
this._config = {
|
|
93
100
|
queueUrl: config.queueUrl,
|
|
@@ -158,8 +165,9 @@ export class SQSPoller {
|
|
|
158
165
|
}
|
|
159
166
|
const arr = this._listeners[event];
|
|
160
167
|
const idx = arr.indexOf(listener);
|
|
161
|
-
if (idx !== -1)
|
|
168
|
+
if (idx !== -1) {
|
|
162
169
|
arr.splice(idx, 1);
|
|
170
|
+
}
|
|
163
171
|
return this;
|
|
164
172
|
}
|
|
165
173
|
start() {
|
|
@@ -170,8 +178,9 @@ export class SQSPoller {
|
|
|
170
178
|
}
|
|
171
179
|
async stop(graceful = true) {
|
|
172
180
|
const run = this._run;
|
|
173
|
-
if (!run)
|
|
181
|
+
if (!run) {
|
|
174
182
|
return { ...this._stats };
|
|
183
|
+
}
|
|
175
184
|
run.stopping = true;
|
|
176
185
|
run.ac.abort();
|
|
177
186
|
if (!graceful) {
|
|
@@ -180,10 +189,12 @@ export class SQSPoller {
|
|
|
180
189
|
}
|
|
181
190
|
if (run.iterator) {
|
|
182
191
|
const outcome = run.graceful ? await this._waitFor(run.done, run) : "hard";
|
|
183
|
-
if (outcome === "timeout")
|
|
192
|
+
if (outcome === "timeout") {
|
|
184
193
|
this._emitShutdownTimeout("the async iterator was not advanced");
|
|
185
|
-
|
|
194
|
+
}
|
|
195
|
+
if (outcome !== "done") {
|
|
186
196
|
await run.iterator.return(undefined);
|
|
197
|
+
}
|
|
187
198
|
}
|
|
188
199
|
await run.done;
|
|
189
200
|
return { ...this._stats };
|
|
@@ -203,36 +214,43 @@ export class SQSPoller {
|
|
|
203
214
|
while (!run.stopping && !this._isAborted(run)) {
|
|
204
215
|
let batch = [];
|
|
205
216
|
try {
|
|
206
|
-
if (!(await this._runBeforeRequest(run)))
|
|
217
|
+
if (!(await this._runBeforeRequest(run))) {
|
|
207
218
|
break;
|
|
219
|
+
}
|
|
208
220
|
const messages = await this._receiveMessages(run);
|
|
209
221
|
run.consecutiveErrors = 0;
|
|
210
222
|
if (messages.length === 0) {
|
|
211
|
-
if (await this._handleEmpty(run))
|
|
223
|
+
if (await this._handleEmpty(run)) {
|
|
212
224
|
break;
|
|
225
|
+
}
|
|
213
226
|
continue;
|
|
214
227
|
}
|
|
215
228
|
this._recordReceived(messages.length);
|
|
216
229
|
batch = messages.map((raw) => this._wrapMessage(raw, run));
|
|
217
|
-
for (const msg of batch)
|
|
230
|
+
for (const msg of batch) {
|
|
218
231
|
this._startHeartbeat(msg, run);
|
|
232
|
+
}
|
|
219
233
|
}
|
|
220
234
|
catch (err) {
|
|
221
|
-
if (this._isAborted(run))
|
|
235
|
+
if (this._isAborted(run)) {
|
|
222
236
|
break;
|
|
237
|
+
}
|
|
223
238
|
await this._handlePollError(err, run);
|
|
224
239
|
continue;
|
|
225
240
|
}
|
|
226
241
|
for (const msg of batch) {
|
|
227
|
-
if (run.stopping || this._isAborted(run))
|
|
242
|
+
if (run.stopping || this._isAborted(run)) {
|
|
228
243
|
break;
|
|
244
|
+
}
|
|
229
245
|
yield msg;
|
|
230
246
|
void this._stopHeartbeat(msg.receiptHandle, run);
|
|
231
|
-
if (this._config.deleteMessages && !msg.handled)
|
|
247
|
+
if (this._config.deleteMessages && !msg.handled) {
|
|
232
248
|
msg.enqueueDelete();
|
|
249
|
+
}
|
|
233
250
|
}
|
|
234
|
-
if (this._config.activePollIntervalMs > 0)
|
|
251
|
+
if (this._config.activePollIntervalMs > 0) {
|
|
235
252
|
await this._delay(this._config.activePollIntervalMs, run);
|
|
253
|
+
}
|
|
236
254
|
}
|
|
237
255
|
}
|
|
238
256
|
finally {
|
|
@@ -240,14 +258,17 @@ export class SQSPoller {
|
|
|
240
258
|
}
|
|
241
259
|
}
|
|
242
260
|
_assertCanStart(activeMessage) {
|
|
243
|
-
if (this._run && !this._run.stopping)
|
|
261
|
+
if (this._run && !this._run.stopping) {
|
|
244
262
|
throw new PollerError(activeMessage);
|
|
245
|
-
|
|
263
|
+
}
|
|
264
|
+
if (this._externalSignal?.aborted) {
|
|
246
265
|
throw new PollerError("abortSignal is already aborted");
|
|
266
|
+
}
|
|
247
267
|
}
|
|
248
268
|
async _beginRun(run) {
|
|
249
|
-
if (run.previous)
|
|
269
|
+
if (run.previous) {
|
|
250
270
|
await run.previous;
|
|
271
|
+
}
|
|
251
272
|
this._stats.pollingStartedAt = new Date();
|
|
252
273
|
this._stats.pollingStoppedAt = null;
|
|
253
274
|
}
|
|
@@ -260,8 +281,9 @@ export class SQSPoller {
|
|
|
260
281
|
run.stopping = true;
|
|
261
282
|
run.finished = true;
|
|
262
283
|
this._stats.pollingStoppedAt = new Date();
|
|
263
|
-
if (this._run === run)
|
|
284
|
+
if (this._run === run) {
|
|
264
285
|
this._run = null;
|
|
286
|
+
}
|
|
265
287
|
run.resolveDone();
|
|
266
288
|
this._emit("stopped", { ...this._stats });
|
|
267
289
|
}
|
|
@@ -286,8 +308,9 @@ export class SQSPoller {
|
|
|
286
308
|
});
|
|
287
309
|
}
|
|
288
310
|
async _waitForDrain(run) {
|
|
289
|
-
if (run.inFlight === 0)
|
|
311
|
+
if (run.inFlight === 0) {
|
|
290
312
|
return;
|
|
313
|
+
}
|
|
291
314
|
const drained = new Promise((resolve) => run.drainResolvers.push(resolve));
|
|
292
315
|
if ((await this._waitFor(drained, run)) === "timeout") {
|
|
293
316
|
this._emitShutdownTimeout(`${run.inFlight} message(s) were still in flight`);
|
|
@@ -301,17 +324,21 @@ export class SQSPoller {
|
|
|
301
324
|
await this._beginRun(run);
|
|
302
325
|
while (!run.stopping && !this._isAborted(run)) {
|
|
303
326
|
try {
|
|
304
|
-
while (!run.stopping && run.inFlight >= this._config.maxConcurrency)
|
|
327
|
+
while (!run.stopping && run.inFlight >= this._config.maxConcurrency) {
|
|
305
328
|
await this._delay(50, run);
|
|
306
|
-
|
|
329
|
+
}
|
|
330
|
+
if (run.stopping || this._isAborted(run)) {
|
|
307
331
|
break;
|
|
308
|
-
|
|
332
|
+
}
|
|
333
|
+
if (!(await this._runBeforeRequest(run))) {
|
|
309
334
|
break;
|
|
335
|
+
}
|
|
310
336
|
const messages = await this._receiveMessages(run, Math.min(this._config.receiveBatchSize, this._config.maxConcurrency - run.inFlight));
|
|
311
337
|
run.consecutiveErrors = 0;
|
|
312
338
|
if (messages.length === 0) {
|
|
313
|
-
if (await this._handleEmpty(run))
|
|
339
|
+
if (await this._handleEmpty(run)) {
|
|
314
340
|
break;
|
|
341
|
+
}
|
|
315
342
|
continue;
|
|
316
343
|
}
|
|
317
344
|
this._recordReceived(messages.length);
|
|
@@ -321,33 +348,39 @@ export class SQSPoller {
|
|
|
321
348
|
void this._processMessage(msg, run).finally(() => {
|
|
322
349
|
run.inFlight--;
|
|
323
350
|
if (run.inFlight === 0) {
|
|
324
|
-
for (const resolve of run.drainResolvers)
|
|
351
|
+
for (const resolve of run.drainResolvers) {
|
|
325
352
|
resolve();
|
|
353
|
+
}
|
|
326
354
|
run.drainResolvers = [];
|
|
327
355
|
}
|
|
328
356
|
});
|
|
329
357
|
}
|
|
330
|
-
if (this._config.activePollIntervalMs > 0)
|
|
358
|
+
if (this._config.activePollIntervalMs > 0) {
|
|
331
359
|
await this._delay(this._config.activePollIntervalMs, run);
|
|
360
|
+
}
|
|
332
361
|
}
|
|
333
362
|
catch (err) {
|
|
334
|
-
if (this._isAborted(run))
|
|
363
|
+
if (this._isAborted(run)) {
|
|
335
364
|
break;
|
|
365
|
+
}
|
|
336
366
|
await this._handlePollError(err, run);
|
|
337
367
|
}
|
|
338
368
|
}
|
|
339
|
-
if (run.graceful)
|
|
369
|
+
if (run.graceful) {
|
|
340
370
|
await this._waitForDrain(run);
|
|
371
|
+
}
|
|
341
372
|
await this._teardown(run);
|
|
342
373
|
}
|
|
343
374
|
async _processMessage(msg, run) {
|
|
344
375
|
this._startHeartbeat(msg, run);
|
|
345
376
|
try {
|
|
346
377
|
const hasListeners = this._listeners.message.length > 0;
|
|
347
|
-
if (hasListeners)
|
|
378
|
+
if (hasListeners) {
|
|
348
379
|
await this._emitAsync("message", msg);
|
|
349
|
-
|
|
380
|
+
}
|
|
381
|
+
if (this._config.deleteMessages && !msg.handled && hasListeners) {
|
|
350
382
|
msg.enqueueDelete();
|
|
383
|
+
}
|
|
351
384
|
}
|
|
352
385
|
catch (err) {
|
|
353
386
|
this._stats.errorCount++;
|
|
@@ -358,8 +391,9 @@ export class SQSPoller {
|
|
|
358
391
|
}
|
|
359
392
|
}
|
|
360
393
|
async _runBeforeRequest(run) {
|
|
361
|
-
if (!this._config.beforeRequest)
|
|
394
|
+
if (!this._config.beforeRequest) {
|
|
362
395
|
return true;
|
|
396
|
+
}
|
|
363
397
|
try {
|
|
364
398
|
await this._config.beforeRequest(this.getStats());
|
|
365
399
|
return true;
|
|
@@ -378,8 +412,9 @@ export class SQSPoller {
|
|
|
378
412
|
return true;
|
|
379
413
|
}
|
|
380
414
|
const delayMs = this._effectiveIdlePollInterval();
|
|
381
|
-
if (delayMs > 0)
|
|
415
|
+
if (delayMs > 0) {
|
|
382
416
|
await this._delay(delayMs, run);
|
|
417
|
+
}
|
|
383
418
|
return false;
|
|
384
419
|
}
|
|
385
420
|
async _handlePollError(err, run) {
|
|
@@ -421,8 +456,9 @@ export class SQSPoller {
|
|
|
421
456
|
clearTimeout(this._deleteTimer);
|
|
422
457
|
this._deleteTimer = null;
|
|
423
458
|
}
|
|
424
|
-
if (this._deleteBatch.length === 0)
|
|
459
|
+
if (this._deleteBatch.length === 0) {
|
|
425
460
|
return;
|
|
461
|
+
}
|
|
426
462
|
const batch = this._deleteBatch.splice(0, this._config.deleteBatchSize);
|
|
427
463
|
const idMap = new Map();
|
|
428
464
|
const entries = batch.map((m, i) => {
|
|
@@ -443,27 +479,32 @@ export class SQSPoller {
|
|
|
443
479
|
this._stats.errorCount++;
|
|
444
480
|
this._emit("error", err instanceof Error ? err : new PollerError(String(err)));
|
|
445
481
|
}
|
|
446
|
-
if (this._deleteBatch.length > 0)
|
|
482
|
+
if (this._deleteBatch.length > 0) {
|
|
447
483
|
await this._flushDeleteBatch();
|
|
484
|
+
}
|
|
448
485
|
}
|
|
449
486
|
_trackFlush(p) {
|
|
450
487
|
this._pendingFlushes.push(p);
|
|
451
488
|
p.finally(() => {
|
|
452
489
|
const i = this._pendingFlushes.indexOf(p);
|
|
453
|
-
if (i !== -1)
|
|
490
|
+
if (i !== -1) {
|
|
454
491
|
this._pendingFlushes.splice(i, 1);
|
|
492
|
+
}
|
|
455
493
|
});
|
|
456
494
|
}
|
|
457
495
|
async _awaitPendingFlushes() {
|
|
458
|
-
while (this._pendingFlushes.length > 0)
|
|
496
|
+
while (this._pendingFlushes.length > 0) {
|
|
459
497
|
await Promise.all([...this._pendingFlushes]);
|
|
498
|
+
}
|
|
460
499
|
}
|
|
461
500
|
_startHeartbeat(msg, run) {
|
|
462
|
-
if (!this._config.extendTimeout || this._config.visibilityTimeoutMs == null)
|
|
501
|
+
if (!this._config.extendTimeout || this._config.visibilityTimeoutMs == null) {
|
|
463
502
|
return;
|
|
503
|
+
}
|
|
464
504
|
const intervalMs = this._config.visibilityTimeoutMs - this._config.extendTimeoutAdvanceMs;
|
|
465
|
-
if (intervalMs <= 0)
|
|
505
|
+
if (intervalMs <= 0) {
|
|
466
506
|
return;
|
|
507
|
+
}
|
|
467
508
|
run.receiptHandles.add(msg.receiptHandle);
|
|
468
509
|
const startTime = Date.now();
|
|
469
510
|
const scheduleNext = () => {
|
|
@@ -493,8 +534,9 @@ export class SQSPoller {
|
|
|
493
534
|
finally {
|
|
494
535
|
this._heartbeatsInFlight.delete(msg.receiptHandle);
|
|
495
536
|
}
|
|
496
|
-
if (this._heartbeatTimers.has(msg.receiptHandle))
|
|
537
|
+
if (this._heartbeatTimers.has(msg.receiptHandle)) {
|
|
497
538
|
scheduleNext();
|
|
539
|
+
}
|
|
498
540
|
}, intervalMs);
|
|
499
541
|
this._heartbeatTimers.set(msg.receiptHandle, timer);
|
|
500
542
|
};
|
|
@@ -537,16 +579,18 @@ export class SQSPoller {
|
|
|
537
579
|
return run.ac.signal.aborted || this._externalSignal?.aborted === true;
|
|
538
580
|
}
|
|
539
581
|
_checkIdleTimeout() {
|
|
540
|
-
if (this._config.idleTimeoutMs == null)
|
|
582
|
+
if (this._config.idleTimeoutMs == null) {
|
|
541
583
|
return false;
|
|
584
|
+
}
|
|
542
585
|
const started = this._stats.pollingStartedAt?.getTime() ?? 0;
|
|
543
586
|
const lastMessage = this._stats.lastMessageReceivedAt?.getTime() ?? 0;
|
|
544
587
|
const since = Math.max(started, lastMessage);
|
|
545
588
|
return since > 0 && Date.now() - since > this._config.idleTimeoutMs;
|
|
546
589
|
}
|
|
547
590
|
_effectiveIdlePollInterval() {
|
|
548
|
-
if (this._config.idlePollIntervalMs > 0)
|
|
591
|
+
if (this._config.idlePollIntervalMs > 0) {
|
|
549
592
|
return this._config.idlePollIntervalMs;
|
|
593
|
+
}
|
|
550
594
|
return this._config.receiveWaitTimeMs === 0 ? MIN_POLL_INTERVAL_MS : 0;
|
|
551
595
|
}
|
|
552
596
|
async _backoff(run) {
|
|
@@ -579,7 +623,8 @@ export class SQSPoller {
|
|
|
579
623
|
}
|
|
580
624
|
}
|
|
581
625
|
async _emitAsync(event, ...args) {
|
|
582
|
-
for (const fn of this._listeners[event])
|
|
626
|
+
for (const fn of this._listeners[event]) {
|
|
583
627
|
await fn(...args);
|
|
628
|
+
}
|
|
584
629
|
}
|
|
585
630
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aws-sdk/lib-sqs",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.1159.0",
|
|
4
4
|
"description": "SQS message poller with auto-delete, backoff, and graceful shutdown",
|
|
5
5
|
"homepage": "https://github.com/aws/aws-sdk-js-v3/tree/main/lib/lib-sqs",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"tslib": "^2.6.2"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
|
-
"@aws-sdk/client-sqs": "3.
|
|
47
|
+
"@aws-sdk/client-sqs": "3.1159.0",
|
|
48
48
|
"@tsconfig/recommended": "1.0.1",
|
|
49
49
|
"@types/node": "^20.14.8",
|
|
50
50
|
"concurrently": "7.0.0",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"typescript": "~7.0.2"
|
|
54
54
|
},
|
|
55
55
|
"peerDependencies": {
|
|
56
|
-
"@aws-sdk/client-sqs": "^3.
|
|
56
|
+
"@aws-sdk/client-sqs": "^3.1159.0"
|
|
57
57
|
},
|
|
58
58
|
"engines": {
|
|
59
59
|
"node": ">=20.0.0"
|