sqs-consumer 7.0.2 → 7.1.0-canary.1

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,17 @@
1
+ body:
2
+ - type: textarea
3
+ attributes:
4
+ label: Background
5
+ description: Why do you think this feature is needed? Are there current alternatives?
6
+ validations:
7
+ required: true
8
+ - type: textarea
9
+ attributes:
10
+ label: Objectives
11
+ description: What should this feature request aim to address?
12
+ value: |
13
+ 1.
14
+ 2.
15
+ 3.
16
+ validations:
17
+ required: true
@@ -0,0 +1,13 @@
1
+ body:
2
+ - type: textarea
3
+ attributes:
4
+ label: Summary
5
+ description: What do you need help with?
6
+ validations:
7
+ required: true
8
+ - type: input
9
+ attributes:
10
+ label: Example
11
+ description: A link to a minimal reproduction is helpful for debugging!
12
+ validations:
13
+ required: false
@@ -0,0 +1,29 @@
1
+ name: "Lock Threads"
2
+
3
+ on:
4
+ schedule:
5
+ - cron: "0 * * * *" # Once a day, at midnight UTC
6
+ workflow_dispatch:
7
+
8
+ permissions:
9
+ issues: write
10
+ pull-requests: write
11
+
12
+ concurrency:
13
+ group: lock
14
+
15
+ jobs:
16
+ action:
17
+ runs-on: ubuntu-latest
18
+ steps:
19
+ - uses: dessant/lock-threads@v4
20
+ with:
21
+ github-token: ${{ secrets.GITHUB_TOKEN }}
22
+ issue-inactive-days: "30" # Lock issues after 30 days of being closed
23
+ pr-inactive-days: "5" # Lock closed PRs after 5 days. This ensures that issues that stem from a PR are opened as issues, rather than comments on the recently merged PR.
24
+ add-issue-labels: "outdated"
25
+ exclude-issue-created-before: "2023-01-01"
26
+ issue-comment: >
27
+ This issue has been closed for more than 30 days. If this issue is still occuring, please open a new issue with more recent context.
28
+ pr-comment: >
29
+ This pull request has already been merged/closed. If you experience issues related to these changes, please open a new issue referencing this pull request.
package/README.md CHANGED
@@ -12,14 +12,14 @@ Build SQS-based applications without the boilerplate. Just define an async funct
12
12
  To install this package, simply enter the following command into your terminal (or the variant of whatever package manager you are using):
13
13
 
14
14
  ```bash
15
- npm install --save-dev sqs-consumer
15
+ npm install sqs-consumer
16
16
  ```
17
17
 
18
18
  > **Note**
19
19
  > This library assumes you are using [AWS SDK v3](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-sqs/index.html). If you are using v2, please install v5.8.0:
20
20
  >
21
21
  > ```bash
22
- > npm install sqs-consumer@5.8.0 --save-dev
22
+ > npm install sqs-consumer@5.8.0
23
23
  > ```
24
24
 
25
25
  ### Node version
@@ -127,6 +127,12 @@ By default, the value of `abort` is set to `false` which means pre existing requ
127
127
 
128
128
  Returns the current polling state of the consumer: `true` if it is actively polling, `false` if it is not.
129
129
 
130
+ ### `consumer.updateOption(option, value)`
131
+
132
+ Updates the provided option with the provided value.
133
+
134
+ You can [find out more about this here](https://bbc.github.io/sqs-consumer/public/classes/Consumer.html#updateOption).
135
+
130
136
  ### Events
131
137
 
132
138
  Each consumer is an [`EventEmitter`](https://nodejs.org/api/events.html) and [emits these events](https://bbc.github.io/sqs-consumer/interfaces/Events.html).
@@ -1,11 +1,9 @@
1
- import { ConsumerOptions, TypedEventEmitter, StopOptions } from './types';
1
+ import { ConsumerOptions, TypedEventEmitter, StopOptions, UpdatableOptions } from './types';
2
2
  /**
3
3
  * [Usage](https://bbc.github.io/sqs-consumer/index.html#usage)
4
4
  */
5
5
  export declare class Consumer extends TypedEventEmitter {
6
6
  private pollingTimeoutId;
7
- private heartbeatTimeoutId;
8
- private handleMessageTimeoutId;
9
7
  private stopped;
10
8
  private queueUrl;
11
9
  private handleMessage;
@@ -39,6 +37,17 @@ export declare class Consumer extends TypedEventEmitter {
39
37
  * Returns the current polling state of the consumer: `true` if it is actively polling, `false` if it is not.
40
38
  */
41
39
  get isRunning(): boolean;
40
+ /**
41
+ * Updates visibilityTimeout to the provided value.
42
+ * @param value The value to set visibilityTimeout to
43
+ */
44
+ private updateVisibilityTimeout;
45
+ /**
46
+ * Updates the provided option to the provided value.
47
+ * @param option The option that you want to update
48
+ * @param value The value to set the option to
49
+ */
50
+ updateOption(option: UpdatableOptions, value: ConsumerOptions[UpdatableOptions]): void;
42
51
  /**
43
52
  * Emit one of the consumer's error events depending on the error received.
44
53
  * @param err The error object to forward on
package/dist/consumer.js CHANGED
@@ -17,8 +17,6 @@ class Consumer extends types_1.TypedEventEmitter {
17
17
  var _a, _b, _c, _d;
18
18
  super();
19
19
  this.pollingTimeoutId = undefined;
20
- this.heartbeatTimeoutId = undefined;
21
- this.handleMessageTimeoutId = undefined;
22
20
  this.stopped = true;
23
21
  /**
24
22
  * A reusable options object for sqs.send that's used to avoid duplication.
@@ -93,6 +91,36 @@ class Consumer extends types_1.TypedEventEmitter {
93
91
  get isRunning() {
94
92
  return !this.stopped;
95
93
  }
94
+ /**
95
+ * Updates visibilityTimeout to the provided value.
96
+ * @param value The value to set visibilityTimeout to
97
+ */
98
+ updateVisibilityTimeout(value) {
99
+ if (typeof value !== 'number') {
100
+ throw new Error('visibilityTimeout must be a number');
101
+ }
102
+ if (typeof value !== 'number' ||
103
+ (this.heartbeatInterval && value <= this.heartbeatInterval)) {
104
+ throw new Error('heartbeatInterval must be less than visibilityTimeout.');
105
+ }
106
+ debug(`Updating the visibilityTimeout option to the value ${value}`);
107
+ this.visibilityTimeout = value;
108
+ this.emit('option_updated', 'visibilityTimeout', value);
109
+ }
110
+ /**
111
+ * Updates the provided option to the provided value.
112
+ * @param option The option that you want to update
113
+ * @param value The value to set the option to
114
+ */
115
+ updateOption(option, value) {
116
+ switch (option) {
117
+ case 'visibilityTimeout':
118
+ this.updateVisibilityTimeout(value);
119
+ break;
120
+ default:
121
+ throw new Error(`The update ${option} cannot be updated`);
122
+ }
123
+ }
96
124
  /**
97
125
  * Emit one of the consumer's error events depending on the error received.
98
126
  * @param err The error object to forward on
@@ -186,10 +214,11 @@ class Consumer extends types_1.TypedEventEmitter {
186
214
  * @param message The message that was delivered from SQS
187
215
  */
188
216
  async processMessage(message) {
217
+ let heartbeatTimeoutId = undefined;
189
218
  try {
190
219
  this.emit('message_received', message);
191
220
  if (this.heartbeatInterval) {
192
- this.heartbeatTimeoutId = this.startHeartbeat(message);
221
+ heartbeatTimeoutId = this.startHeartbeat(message);
193
222
  }
194
223
  const ackedMessage = await this.executeHandler(message);
195
224
  if ((ackedMessage === null || ackedMessage === void 0 ? void 0 : ackedMessage.MessageId) === message.MessageId) {
@@ -204,8 +233,7 @@ class Consumer extends types_1.TypedEventEmitter {
204
233
  }
205
234
  }
206
235
  finally {
207
- clearInterval(this.heartbeatTimeoutId);
208
- this.heartbeatTimeoutId = undefined;
236
+ clearInterval(heartbeatTimeoutId);
209
237
  }
210
238
  }
211
239
  /**
@@ -213,12 +241,13 @@ class Consumer extends types_1.TypedEventEmitter {
213
241
  * @param messages The messages that were delivered from SQS
214
242
  */
215
243
  async processMessageBatch(messages) {
244
+ let heartbeatTimeoutId = undefined;
216
245
  try {
217
246
  messages.forEach((message) => {
218
247
  this.emit('message_received', message);
219
248
  });
220
249
  if (this.heartbeatInterval) {
221
- this.heartbeatTimeoutId = this.startHeartbeat(null, messages);
250
+ heartbeatTimeoutId = this.startHeartbeat(null, messages);
222
251
  }
223
252
  const ackedMessages = await this.executeBatchHandler(messages);
224
253
  if ((ackedMessages === null || ackedMessages === void 0 ? void 0 : ackedMessages.length) > 0) {
@@ -235,8 +264,7 @@ class Consumer extends types_1.TypedEventEmitter {
235
264
  }
236
265
  }
237
266
  finally {
238
- clearInterval(this.heartbeatTimeoutId);
239
- this.heartbeatTimeoutId = undefined;
267
+ clearInterval(heartbeatTimeoutId);
240
268
  }
241
269
  }
242
270
  /**
@@ -297,11 +325,12 @@ class Consumer extends types_1.TypedEventEmitter {
297
325
  * @param message The message that was received from SQS
298
326
  */
299
327
  async executeHandler(message) {
328
+ let handleMessageTimeoutId = undefined;
300
329
  try {
301
330
  let result;
302
331
  if (this.handleMessageTimeout) {
303
332
  const pending = new Promise((_, reject) => {
304
- this.handleMessageTimeoutId = setTimeout(() => {
333
+ handleMessageTimeoutId = setTimeout(() => {
305
334
  reject(new errors_1.TimeoutError());
306
335
  }, this.handleMessageTimeout);
307
336
  });
@@ -320,8 +349,8 @@ class Consumer extends types_1.TypedEventEmitter {
320
349
  throw err;
321
350
  }
322
351
  finally {
323
- if (this.handleMessageTimeoutId) {
324
- clearTimeout(this.handleMessageTimeoutId);
352
+ if (handleMessageTimeoutId) {
353
+ clearTimeout(handleMessageTimeoutId);
325
354
  }
326
355
  }
327
356
  }
package/dist/types.d.ts CHANGED
@@ -69,7 +69,7 @@ export interface ConsumerOptions {
69
69
  sqs?: SQSClient;
70
70
  /**
71
71
  * The AWS region.
72
- * @defaultValue `eu-west-1`
72
+ * @defaultValue process.env.AWS_REGION || `eu-west-1`
73
73
  */
74
74
  region?: string;
75
75
  /**
@@ -105,6 +105,7 @@ export interface ConsumerOptions {
105
105
  */
106
106
  handleMessageBatch?(messages: Message[]): Promise<Message[] | void>;
107
107
  }
108
+ export type UpdatableOptions = 'visibilityTimeout';
108
109
  export interface StopOptions {
109
110
  /**
110
111
  * Default to `false`, if you want the stop action to also abort requests to SQS
@@ -153,6 +154,10 @@ export interface Events {
153
154
  * Fired when the consumer finally stops its work.
154
155
  */
155
156
  stopped: [];
157
+ /**
158
+ * Fired when an option is updated
159
+ */
160
+ option_updated: [UpdatableOptions, ConsumerOptions[UpdatableOptions]];
156
161
  }
157
162
  export declare class TypedEventEmitter extends EventEmitter {
158
163
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sqs-consumer",
3
- "version": "7.0.2",
3
+ "version": "7.1.0-canary.1",
4
4
  "description": "Build SQS-based Node applications without the boilerplate",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/src/consumer.ts CHANGED
@@ -17,7 +17,12 @@ import {
17
17
  } from '@aws-sdk/client-sqs';
18
18
  import Debug from 'debug';
19
19
 
20
- import { ConsumerOptions, TypedEventEmitter, StopOptions } from './types';
20
+ import {
21
+ ConsumerOptions,
22
+ TypedEventEmitter,
23
+ StopOptions,
24
+ UpdatableOptions
25
+ } from './types';
21
26
  import { autoBind } from './bind';
22
27
  import {
23
28
  SQSError,
@@ -35,8 +40,6 @@ const debug = Debug('sqs-consumer');
35
40
  */
36
41
  export class Consumer extends TypedEventEmitter {
37
42
  private pollingTimeoutId: NodeJS.Timeout | undefined = undefined;
38
- private heartbeatTimeoutId: NodeJS.Timeout | undefined = undefined;
39
- private handleMessageTimeoutId: NodeJS.Timeout | undefined = undefined;
40
43
  private stopped = true;
41
44
  private queueUrl: string;
42
45
  private handleMessage: (message: Message) => Promise<Message | void>;
@@ -134,6 +137,47 @@ export class Consumer extends TypedEventEmitter {
134
137
  return !this.stopped;
135
138
  }
136
139
 
140
+ /**
141
+ * Updates visibilityTimeout to the provided value.
142
+ * @param value The value to set visibilityTimeout to
143
+ */
144
+ private updateVisibilityTimeout(value: ConsumerOptions['visibilityTimeout']) {
145
+ if (typeof value !== 'number') {
146
+ throw new Error('visibilityTimeout must be a number');
147
+ }
148
+
149
+ if (
150
+ typeof value !== 'number' ||
151
+ (this.heartbeatInterval && value <= this.heartbeatInterval)
152
+ ) {
153
+ throw new Error('heartbeatInterval must be less than visibilityTimeout.');
154
+ }
155
+
156
+ debug(`Updating the visibilityTimeout option to the value ${value}`);
157
+
158
+ this.visibilityTimeout = value;
159
+
160
+ this.emit('option_updated', 'visibilityTimeout', value);
161
+ }
162
+
163
+ /**
164
+ * Updates the provided option to the provided value.
165
+ * @param option The option that you want to update
166
+ * @param value The value to set the option to
167
+ */
168
+ public updateOption(
169
+ option: UpdatableOptions,
170
+ value: ConsumerOptions[UpdatableOptions]
171
+ ) {
172
+ switch (option) {
173
+ case 'visibilityTimeout':
174
+ this.updateVisibilityTimeout(value);
175
+ break;
176
+ default:
177
+ throw new Error(`The update ${option} cannot be updated`);
178
+ }
179
+ }
180
+
137
181
  /**
138
182
  * Emit one of the consumer's error events depending on the error received.
139
183
  * @param err The error object to forward on
@@ -242,11 +286,13 @@ export class Consumer extends TypedEventEmitter {
242
286
  * @param message The message that was delivered from SQS
243
287
  */
244
288
  private async processMessage(message: Message): Promise<void> {
289
+ let heartbeatTimeoutId: NodeJS.Timeout | undefined = undefined;
290
+
245
291
  try {
246
292
  this.emit('message_received', message);
247
293
 
248
294
  if (this.heartbeatInterval) {
249
- this.heartbeatTimeoutId = this.startHeartbeat(message);
295
+ heartbeatTimeoutId = this.startHeartbeat(message);
250
296
  }
251
297
 
252
298
  const ackedMessage = await this.executeHandler(message);
@@ -263,8 +309,7 @@ export class Consumer extends TypedEventEmitter {
263
309
  await this.changeVisibilityTimeout(message, 0);
264
310
  }
265
311
  } finally {
266
- clearInterval(this.heartbeatTimeoutId);
267
- this.heartbeatTimeoutId = undefined;
312
+ clearInterval(heartbeatTimeoutId);
268
313
  }
269
314
  }
270
315
 
@@ -273,13 +318,15 @@ export class Consumer extends TypedEventEmitter {
273
318
  * @param messages The messages that were delivered from SQS
274
319
  */
275
320
  private async processMessageBatch(messages: Message[]): Promise<void> {
321
+ let heartbeatTimeoutId: NodeJS.Timeout | undefined = undefined;
322
+
276
323
  try {
277
324
  messages.forEach((message) => {
278
325
  this.emit('message_received', message);
279
326
  });
280
327
 
281
328
  if (this.heartbeatInterval) {
282
- this.heartbeatTimeoutId = this.startHeartbeat(null, messages);
329
+ heartbeatTimeoutId = this.startHeartbeat(null, messages);
283
330
  }
284
331
 
285
332
  const ackedMessages = await this.executeBatchHandler(messages);
@@ -298,8 +345,7 @@ export class Consumer extends TypedEventEmitter {
298
345
  await this.changeVisibilityTimeoutBatch(messages, 0);
299
346
  }
300
347
  } finally {
301
- clearInterval(this.heartbeatTimeoutId);
302
- this.heartbeatTimeoutId = undefined;
348
+ clearInterval(heartbeatTimeoutId);
303
349
  }
304
350
  }
305
351
 
@@ -387,12 +433,14 @@ export class Consumer extends TypedEventEmitter {
387
433
  * @param message The message that was received from SQS
388
434
  */
389
435
  private async executeHandler(message: Message): Promise<Message> {
436
+ let handleMessageTimeoutId: NodeJS.Timeout | undefined = undefined;
437
+
390
438
  try {
391
439
  let result;
392
440
 
393
441
  if (this.handleMessageTimeout) {
394
442
  const pending = new Promise((_, reject) => {
395
- this.handleMessageTimeoutId = setTimeout((): void => {
443
+ handleMessageTimeoutId = setTimeout((): void => {
396
444
  reject(new TimeoutError());
397
445
  }, this.handleMessageTimeout);
398
446
  });
@@ -409,8 +457,8 @@ export class Consumer extends TypedEventEmitter {
409
457
  : `Unexpected message handler failure: ${err.message}`;
410
458
  throw err;
411
459
  } finally {
412
- if (this.handleMessageTimeoutId) {
413
- clearTimeout(this.handleMessageTimeoutId);
460
+ if (handleMessageTimeoutId) {
461
+ clearTimeout(handleMessageTimeoutId);
414
462
  }
415
463
  }
416
464
  }
package/src/types.ts CHANGED
@@ -69,7 +69,7 @@ export interface ConsumerOptions {
69
69
  sqs?: SQSClient;
70
70
  /**
71
71
  * The AWS region.
72
- * @defaultValue `eu-west-1`
72
+ * @defaultValue process.env.AWS_REGION || `eu-west-1`
73
73
  */
74
74
  region?: string;
75
75
  /**
@@ -106,6 +106,8 @@ export interface ConsumerOptions {
106
106
  handleMessageBatch?(messages: Message[]): Promise<Message[] | void>;
107
107
  }
108
108
 
109
+ export type UpdatableOptions = 'visibilityTimeout';
110
+
109
111
  export interface StopOptions {
110
112
  /**
111
113
  * Default to `false`, if you want the stop action to also abort requests to SQS
@@ -155,6 +157,10 @@ export interface Events {
155
157
  * Fired when the consumer finally stops its work.
156
158
  */
157
159
  stopped: [];
160
+ /**
161
+ * Fired when an option is updated
162
+ */
163
+ option_updated: [UpdatableOptions, ConsumerOptions[UpdatableOptions]];
158
164
  }
159
165
 
160
166
  export class TypedEventEmitter extends EventEmitter {