sqs-consumer 5.6.0 → 5.8.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/.github/CODEOWNERS +2 -2
- package/.github/CODE_OF_CONDUCT.md +74 -0
- package/.github/CONTRIBUTING.md +14 -12
- package/.github/ISSUE_TEMPLATE/bug-report.md +2 -2
- package/.github/ISSUE_TEMPLATE/feature-request.md +0 -1
- package/.github/ISSUE_TEMPLATE/technical-question.md +0 -1
- package/.github/SECURITY.md +9 -0
- package/.github/pull_request_template.md +20 -11
- package/.github/workflows/coverage.yml +35 -0
- package/.github/workflows/stale.yml +20 -0
- package/.github/workflows/test.yml +34 -0
- package/.prettierignore +4 -0
- package/.prettierrc.js +5 -0
- package/README.md +41 -39
- package/dist/consumer.d.ts +13 -11
- package/dist/consumer.js +45 -37
- package/dist/index.js +1 -0
- package/package.json +47 -29
- package/src/consumer.ts +105 -54
- package/src/errors.ts +1 -4
- package/test/{consumer.ts → consumer.test.ts} +147 -32
- package/tsconfig.json +3 -8
- package/.travis.yml +0 -10
package/dist/consumer.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Consumer = void 0;
|
|
4
|
-
const
|
|
5
|
-
const
|
|
4
|
+
const aws_sdk_1 = require("aws-sdk");
|
|
5
|
+
const debug_1 = require("debug");
|
|
6
6
|
const events_1 = require("events");
|
|
7
7
|
const bind_1 = require("./bind");
|
|
8
8
|
const errors_1 = require("./errors");
|
|
9
|
-
const debug =
|
|
9
|
+
const debug = (0, debug_1.default)('sqs-consumer');
|
|
10
10
|
const requiredOptions = [
|
|
11
11
|
'queueUrl',
|
|
12
12
|
// only one of handleMessage / handleMessagesBatch is required
|
|
@@ -31,13 +31,16 @@ function assertOptions(options) {
|
|
|
31
31
|
if (options.batchSize > 10 || options.batchSize < 1) {
|
|
32
32
|
throw new Error('SQS batchSize option must be between 1 and 10.');
|
|
33
33
|
}
|
|
34
|
-
if (options.heartbeatInterval &&
|
|
34
|
+
if (options.heartbeatInterval &&
|
|
35
|
+
!(options.heartbeatInterval < options.visibilityTimeout)) {
|
|
35
36
|
throw new Error('heartbeatInterval must be less than visibilityTimeout.');
|
|
36
37
|
}
|
|
37
38
|
}
|
|
38
39
|
function isConnectionError(err) {
|
|
39
40
|
if (err instanceof errors_1.SQSError) {
|
|
40
|
-
return (err.statusCode === 403 ||
|
|
41
|
+
return (err.statusCode === 403 ||
|
|
42
|
+
err.code === 'CredentialsError' ||
|
|
43
|
+
err.code === 'UnknownEndpoint');
|
|
41
44
|
}
|
|
42
45
|
return false;
|
|
43
46
|
}
|
|
@@ -56,6 +59,7 @@ function hasMessages(response) {
|
|
|
56
59
|
}
|
|
57
60
|
class Consumer extends events_1.EventEmitter {
|
|
58
61
|
constructor(options) {
|
|
62
|
+
var _a, _b, _c, _d;
|
|
59
63
|
super();
|
|
60
64
|
assertOptions(options);
|
|
61
65
|
this.queueUrl = options.queueUrl;
|
|
@@ -67,15 +71,20 @@ class Consumer extends events_1.EventEmitter {
|
|
|
67
71
|
this.stopped = true;
|
|
68
72
|
this.batchSize = options.batchSize || 1;
|
|
69
73
|
this.visibilityTimeout = options.visibilityTimeout;
|
|
70
|
-
this.terminateVisibilityTimeout =
|
|
74
|
+
this.terminateVisibilityTimeout =
|
|
75
|
+
options.terminateVisibilityTimeout || false;
|
|
71
76
|
this.heartbeatInterval = options.heartbeatInterval;
|
|
72
|
-
this.waitTimeSeconds = options.waitTimeSeconds
|
|
73
|
-
this.authenticationErrorTimeout =
|
|
74
|
-
|
|
75
|
-
this.
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
77
|
+
this.waitTimeSeconds = (_a = options.waitTimeSeconds) !== null && _a !== void 0 ? _a : 20;
|
|
78
|
+
this.authenticationErrorTimeout =
|
|
79
|
+
(_b = options.authenticationErrorTimeout) !== null && _b !== void 0 ? _b : 10000;
|
|
80
|
+
this.pollingWaitTimeMs = (_c = options.pollingWaitTimeMs) !== null && _c !== void 0 ? _c : 0;
|
|
81
|
+
this.shouldDeleteMessages = (_d = options.shouldDeleteMessages) !== null && _d !== void 0 ? _d : true;
|
|
82
|
+
this.sqs =
|
|
83
|
+
options.sqs ||
|
|
84
|
+
new aws_sdk_1.SQS({
|
|
85
|
+
region: options.region || process.env.AWS_REGION || 'eu-west-1'
|
|
86
|
+
});
|
|
87
|
+
(0, bind_1.autoBind)(this);
|
|
79
88
|
}
|
|
80
89
|
emit(event, ...args) {
|
|
81
90
|
return super.emit(event, ...args);
|
|
@@ -128,7 +137,7 @@ class Consumer extends events_1.EventEmitter {
|
|
|
128
137
|
try {
|
|
129
138
|
if (this.heartbeatInterval) {
|
|
130
139
|
heartbeat = this.startHeartbeat(async () => {
|
|
131
|
-
return this.
|
|
140
|
+
return this.changeVisibilityTimeout(message, this.visibilityTimeout);
|
|
132
141
|
});
|
|
133
142
|
}
|
|
134
143
|
await this.executeHandler(message);
|
|
@@ -138,7 +147,7 @@ class Consumer extends events_1.EventEmitter {
|
|
|
138
147
|
catch (err) {
|
|
139
148
|
this.emitError(err, message);
|
|
140
149
|
if (this.terminateVisibilityTimeout) {
|
|
141
|
-
await this.
|
|
150
|
+
await this.changeVisibilityTimeout(message, 0);
|
|
142
151
|
}
|
|
143
152
|
}
|
|
144
153
|
finally {
|
|
@@ -147,24 +156,24 @@ class Consumer extends events_1.EventEmitter {
|
|
|
147
156
|
}
|
|
148
157
|
async receiveMessage(params) {
|
|
149
158
|
try {
|
|
150
|
-
return await this.sqs
|
|
151
|
-
.receiveMessage(params)
|
|
152
|
-
.promise();
|
|
159
|
+
return await this.sqs.receiveMessage(params).promise();
|
|
153
160
|
}
|
|
154
161
|
catch (err) {
|
|
155
162
|
throw toSQSError(err, `SQS receive message failed: ${err.message}`);
|
|
156
163
|
}
|
|
157
164
|
}
|
|
158
165
|
async deleteMessage(message) {
|
|
166
|
+
if (!this.shouldDeleteMessages) {
|
|
167
|
+
debug('Skipping message delete since shouldDeleteMessages is set to false');
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
159
170
|
debug('Deleting message %s', message.MessageId);
|
|
160
171
|
const deleteParams = {
|
|
161
172
|
QueueUrl: this.queueUrl,
|
|
162
173
|
ReceiptHandle: message.ReceiptHandle
|
|
163
174
|
};
|
|
164
175
|
try {
|
|
165
|
-
await this.sqs
|
|
166
|
-
.deleteMessage(deleteParams)
|
|
167
|
-
.promise();
|
|
176
|
+
await this.sqs.deleteMessage(deleteParams).promise();
|
|
168
177
|
}
|
|
169
178
|
catch (err) {
|
|
170
179
|
throw toSQSError(err, `SQS delete message failed: ${err.message}`);
|
|
@@ -176,10 +185,7 @@ class Consumer extends events_1.EventEmitter {
|
|
|
176
185
|
try {
|
|
177
186
|
if (this.handleMessageTimeout) {
|
|
178
187
|
[timeout, pending] = createTimeout(this.handleMessageTimeout);
|
|
179
|
-
await Promise.race([
|
|
180
|
-
this.handleMessage(message),
|
|
181
|
-
pending
|
|
182
|
-
]);
|
|
188
|
+
await Promise.race([this.handleMessage(message), pending]);
|
|
183
189
|
}
|
|
184
190
|
else {
|
|
185
191
|
await this.handleMessage(message);
|
|
@@ -198,9 +204,9 @@ class Consumer extends events_1.EventEmitter {
|
|
|
198
204
|
clearTimeout(timeout);
|
|
199
205
|
}
|
|
200
206
|
}
|
|
201
|
-
async
|
|
207
|
+
async changeVisibilityTimeout(message, timeout) {
|
|
202
208
|
try {
|
|
203
|
-
return this.sqs
|
|
209
|
+
return await this.sqs
|
|
204
210
|
.changeMessageVisibility({
|
|
205
211
|
QueueUrl: this.queueUrl,
|
|
206
212
|
ReceiptHandle: message.ReceiptHandle,
|
|
@@ -209,7 +215,7 @@ class Consumer extends events_1.EventEmitter {
|
|
|
209
215
|
.promise();
|
|
210
216
|
}
|
|
211
217
|
catch (err) {
|
|
212
|
-
this.emit('error', err, message);
|
|
218
|
+
this.emit('error', toSQSError(err, `Error changing visibility timeout: ${err.message}`), message);
|
|
213
219
|
}
|
|
214
220
|
}
|
|
215
221
|
emitError(err, message) {
|
|
@@ -247,9 +253,11 @@ class Consumer extends events_1.EventEmitter {
|
|
|
247
253
|
currentPollingTimeout = this.authenticationErrorTimeout;
|
|
248
254
|
}
|
|
249
255
|
return;
|
|
250
|
-
})
|
|
256
|
+
})
|
|
257
|
+
.then(() => {
|
|
251
258
|
setTimeout(this.poll, currentPollingTimeout);
|
|
252
|
-
})
|
|
259
|
+
})
|
|
260
|
+
.catch((err) => {
|
|
253
261
|
this.emit('error', err);
|
|
254
262
|
});
|
|
255
263
|
}
|
|
@@ -281,6 +289,10 @@ class Consumer extends events_1.EventEmitter {
|
|
|
281
289
|
}
|
|
282
290
|
}
|
|
283
291
|
async deleteMessageBatch(messages) {
|
|
292
|
+
if (!this.shouldDeleteMessages) {
|
|
293
|
+
debug('Skipping message delete since shouldDeleteMessages is set to false');
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
284
296
|
debug('Deleting messages %s', messages.map((msg) => msg.MessageId).join(' ,'));
|
|
285
297
|
const deleteParams = {
|
|
286
298
|
QueueUrl: this.queueUrl,
|
|
@@ -290,9 +302,7 @@ class Consumer extends events_1.EventEmitter {
|
|
|
290
302
|
}))
|
|
291
303
|
};
|
|
292
304
|
try {
|
|
293
|
-
await this.sqs
|
|
294
|
-
.deleteMessageBatch(deleteParams)
|
|
295
|
-
.promise();
|
|
305
|
+
await this.sqs.deleteMessageBatch(deleteParams).promise();
|
|
296
306
|
}
|
|
297
307
|
catch (err) {
|
|
298
308
|
throw toSQSError(err, `SQS delete message failed: ${err.message}`);
|
|
@@ -317,12 +327,10 @@ class Consumer extends events_1.EventEmitter {
|
|
|
317
327
|
}))
|
|
318
328
|
};
|
|
319
329
|
try {
|
|
320
|
-
return this.sqs
|
|
321
|
-
.changeMessageVisibilityBatch(params)
|
|
322
|
-
.promise();
|
|
330
|
+
return await this.sqs.changeMessageVisibilityBatch(params).promise();
|
|
323
331
|
}
|
|
324
332
|
catch (err) {
|
|
325
|
-
this.emit('error', err, messages);
|
|
333
|
+
this.emit('error', toSQSError(err, `Error changing visibility timeout: ${err.message}`), messages);
|
|
326
334
|
}
|
|
327
335
|
}
|
|
328
336
|
startHeartbeat(heartbeatFn) {
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sqs-consumer",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.8.0",
|
|
4
4
|
"description": "Build SQS-based Node applications without the boilerplate",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -11,11 +11,13 @@
|
|
|
11
11
|
"prepublish": "npm run build",
|
|
12
12
|
"pretest": "npm run build",
|
|
13
13
|
"test": "mocha --recursive --full-trace --exit",
|
|
14
|
-
"lint": "eslint . --ext .ts",
|
|
15
|
-
"lint:fix": "eslint . --fix",
|
|
16
14
|
"coverage": "nyc mocha && nyc report --reporter=html && nyc report --reporter=json-summary",
|
|
17
15
|
"lcov": "nyc mocha && nyc report --reporter=lcov",
|
|
18
|
-
"
|
|
16
|
+
"lint": "eslint . --ext .ts",
|
|
17
|
+
"lint:fix": "eslint . --fix",
|
|
18
|
+
"format": "prettier --loglevel warn --write \"**/*.{js,json,jsx,md,ts,tsx,html}\"",
|
|
19
|
+
"format:check": "prettier --check \"**/*.{js,json,jsx,md,ts,tsx,html}\"",
|
|
20
|
+
"posttest": "npm run lint && npm run format:check"
|
|
19
21
|
},
|
|
20
22
|
"repository": {
|
|
21
23
|
"type": "git",
|
|
@@ -32,31 +34,33 @@
|
|
|
32
34
|
],
|
|
33
35
|
"license": "Apache-2.0",
|
|
34
36
|
"devDependencies": {
|
|
35
|
-
"@types/chai": "^4.
|
|
36
|
-
"@types/debug": "^4.1.
|
|
37
|
-
"@types/mocha": "^
|
|
38
|
-
"@types/node": "^
|
|
39
|
-
"@types/sinon": "^
|
|
40
|
-
"
|
|
41
|
-
"
|
|
42
|
-
"
|
|
43
|
-
"eslint": "^
|
|
44
|
-
"
|
|
45
|
-
"mocha": "^8.0.1",
|
|
37
|
+
"@types/chai": "^4.3.4",
|
|
38
|
+
"@types/debug": "^4.1.7",
|
|
39
|
+
"@types/mocha": "^10.0.1",
|
|
40
|
+
"@types/node": "^16.18.7",
|
|
41
|
+
"@types/sinon": "^10.0.13",
|
|
42
|
+
"chai": "^4.3.7",
|
|
43
|
+
"eslint": "^8.29.0",
|
|
44
|
+
"eslint-config-iplayer-ts": "^4.1.0",
|
|
45
|
+
"eslint-config-prettier": "^4.3.0",
|
|
46
|
+
"mocha": "^10.1.0",
|
|
46
47
|
"nyc": "^15.1.0",
|
|
47
48
|
"p-event": "^4.2.0",
|
|
48
|
-
"
|
|
49
|
-
"
|
|
50
|
-
"
|
|
51
|
-
"
|
|
52
|
-
"typescript": "^3.9.5",
|
|
53
|
-
"aws-sdk": "^2.699.0"
|
|
49
|
+
"prettier": "^2.8.1",
|
|
50
|
+
"sinon": "^15.0.0",
|
|
51
|
+
"ts-node": "^10.9.1",
|
|
52
|
+
"typescript": "^4.9.4"
|
|
54
53
|
},
|
|
55
54
|
"dependencies": {
|
|
56
|
-
"
|
|
55
|
+
"aws-sdk": "^2.1271.0",
|
|
56
|
+
"debug": "^4.3.4"
|
|
57
57
|
},
|
|
58
58
|
"peerDependencies": {
|
|
59
|
-
"aws-sdk": "^2.
|
|
59
|
+
"aws-sdk": "^2.1271.0"
|
|
60
|
+
},
|
|
61
|
+
"mocha": {
|
|
62
|
+
"spec": "test/**/**/*.test.ts",
|
|
63
|
+
"require": "ts-node/register"
|
|
60
64
|
},
|
|
61
65
|
"nyc": {
|
|
62
66
|
"include": [
|
|
@@ -72,14 +76,28 @@
|
|
|
72
76
|
"instrument": true
|
|
73
77
|
},
|
|
74
78
|
"eslintConfig": {
|
|
75
|
-
"extends":
|
|
79
|
+
"extends": [
|
|
80
|
+
"iplayer-ts",
|
|
81
|
+
"prettier",
|
|
82
|
+
"prettier/react",
|
|
83
|
+
"prettier/@typescript-eslint"
|
|
84
|
+
],
|
|
76
85
|
"parserOptions": {
|
|
77
|
-
"ecmaVersion": 2017,
|
|
78
86
|
"sourceType": "module"
|
|
87
|
+
},
|
|
88
|
+
"rules": {
|
|
89
|
+
"@typescript-eslint/naming-convention": [
|
|
90
|
+
"error",
|
|
91
|
+
{
|
|
92
|
+
"selector": "variable",
|
|
93
|
+
"format": [
|
|
94
|
+
"camelCase",
|
|
95
|
+
"UPPER_CASE",
|
|
96
|
+
"PascalCase"
|
|
97
|
+
],
|
|
98
|
+
"leadingUnderscore": "allow"
|
|
99
|
+
}
|
|
100
|
+
]
|
|
79
101
|
}
|
|
80
|
-
},
|
|
81
|
-
"mocha": {
|
|
82
|
-
"spec": "test/**/**/*.ts",
|
|
83
|
-
"require": "ts-node/register"
|
|
84
102
|
}
|
|
85
103
|
}
|
package/src/consumer.ts
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
|
-
import { AWSError } from 'aws-sdk';
|
|
2
|
-
import * as SQS from 'aws-sdk/clients/sqs';
|
|
1
|
+
import { AWSError, SQS } from 'aws-sdk';
|
|
3
2
|
import { PromiseResult } from 'aws-sdk/lib/request';
|
|
4
|
-
import
|
|
3
|
+
import Debug from 'debug';
|
|
5
4
|
import { EventEmitter } from 'events';
|
|
6
5
|
import { autoBind } from './bind';
|
|
7
6
|
import { SQSError, TimeoutError } from './errors';
|
|
8
7
|
|
|
9
8
|
const debug = Debug('sqs-consumer');
|
|
10
9
|
|
|
11
|
-
type ReceieveMessageResponse = PromiseResult<
|
|
10
|
+
type ReceieveMessageResponse = PromiseResult<
|
|
11
|
+
SQS.Types.ReceiveMessageResult,
|
|
12
|
+
AWSError
|
|
13
|
+
>;
|
|
12
14
|
type ReceiveMessageRequest = SQS.Types.ReceiveMessageRequest;
|
|
13
15
|
export type SQSMessage = SQS.Types.Message;
|
|
14
16
|
|
|
@@ -37,7 +39,9 @@ function assertOptions(options: ConsumerOptions): void {
|
|
|
37
39
|
requiredOptions.forEach((option) => {
|
|
38
40
|
const possibilities = option.split('|');
|
|
39
41
|
if (!possibilities.find((p) => options[p])) {
|
|
40
|
-
throw new Error(
|
|
42
|
+
throw new Error(
|
|
43
|
+
`Missing SQS consumer option [ ${possibilities.join(' or ')} ].`
|
|
44
|
+
);
|
|
41
45
|
}
|
|
42
46
|
});
|
|
43
47
|
|
|
@@ -45,14 +49,21 @@ function assertOptions(options: ConsumerOptions): void {
|
|
|
45
49
|
throw new Error('SQS batchSize option must be between 1 and 10.');
|
|
46
50
|
}
|
|
47
51
|
|
|
48
|
-
if (
|
|
52
|
+
if (
|
|
53
|
+
options.heartbeatInterval &&
|
|
54
|
+
!(options.heartbeatInterval < options.visibilityTimeout)
|
|
55
|
+
) {
|
|
49
56
|
throw new Error('heartbeatInterval must be less than visibilityTimeout.');
|
|
50
57
|
}
|
|
51
58
|
}
|
|
52
59
|
|
|
53
60
|
function isConnectionError(err: Error): boolean {
|
|
54
61
|
if (err instanceof SQSError) {
|
|
55
|
-
return (
|
|
62
|
+
return (
|
|
63
|
+
err.statusCode === 403 ||
|
|
64
|
+
err.code === 'CredentialsError' ||
|
|
65
|
+
err.code === 'UnknownEndpoint'
|
|
66
|
+
);
|
|
56
67
|
}
|
|
57
68
|
return false;
|
|
58
69
|
}
|
|
@@ -88,19 +99,20 @@ export interface ConsumerOptions {
|
|
|
88
99
|
sqs?: SQS;
|
|
89
100
|
region?: string;
|
|
90
101
|
handleMessageTimeout?: number;
|
|
102
|
+
shouldDeleteMessages?: boolean;
|
|
91
103
|
handleMessage?(message: SQSMessage): Promise<void>;
|
|
92
104
|
handleMessageBatch?(messages: SQSMessage[]): Promise<void>;
|
|
93
105
|
}
|
|
94
106
|
|
|
95
107
|
interface Events {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
108
|
+
response_processed: [];
|
|
109
|
+
empty: [];
|
|
110
|
+
message_received: [SQSMessage];
|
|
111
|
+
message_processed: [SQSMessage];
|
|
112
|
+
error: [Error, void | SQSMessage | SQSMessage[]];
|
|
113
|
+
timeout_error: [Error, SQSMessage];
|
|
114
|
+
processing_error: [Error, SQSMessage];
|
|
115
|
+
stopped: [];
|
|
104
116
|
}
|
|
105
117
|
|
|
106
118
|
export class Consumer extends EventEmitter {
|
|
@@ -119,6 +131,7 @@ export class Consumer extends EventEmitter {
|
|
|
119
131
|
private terminateVisibilityTimeout: boolean;
|
|
120
132
|
private heartbeatInterval: number;
|
|
121
133
|
private sqs: SQS;
|
|
134
|
+
private shouldDeleteMessages: boolean;
|
|
122
135
|
|
|
123
136
|
constructor(options: ConsumerOptions) {
|
|
124
137
|
super();
|
|
@@ -132,15 +145,20 @@ export class Consumer extends EventEmitter {
|
|
|
132
145
|
this.stopped = true;
|
|
133
146
|
this.batchSize = options.batchSize || 1;
|
|
134
147
|
this.visibilityTimeout = options.visibilityTimeout;
|
|
135
|
-
this.terminateVisibilityTimeout =
|
|
148
|
+
this.terminateVisibilityTimeout =
|
|
149
|
+
options.terminateVisibilityTimeout || false;
|
|
136
150
|
this.heartbeatInterval = options.heartbeatInterval;
|
|
137
|
-
this.waitTimeSeconds = options.waitTimeSeconds
|
|
138
|
-
this.authenticationErrorTimeout =
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
this.
|
|
142
|
-
|
|
143
|
-
|
|
151
|
+
this.waitTimeSeconds = options.waitTimeSeconds ?? 20;
|
|
152
|
+
this.authenticationErrorTimeout =
|
|
153
|
+
options.authenticationErrorTimeout ?? 10000;
|
|
154
|
+
this.pollingWaitTimeMs = options.pollingWaitTimeMs ?? 0;
|
|
155
|
+
this.shouldDeleteMessages = options.shouldDeleteMessages ?? true;
|
|
156
|
+
|
|
157
|
+
this.sqs =
|
|
158
|
+
options.sqs ||
|
|
159
|
+
new SQS({
|
|
160
|
+
region: options.region || process.env.AWS_REGION || 'eu-west-1'
|
|
161
|
+
});
|
|
144
162
|
|
|
145
163
|
autoBind(this);
|
|
146
164
|
}
|
|
@@ -149,11 +167,17 @@ export class Consumer extends EventEmitter {
|
|
|
149
167
|
return super.emit(event, ...args);
|
|
150
168
|
}
|
|
151
169
|
|
|
152
|
-
on<T extends keyof Events>(
|
|
170
|
+
on<T extends keyof Events>(
|
|
171
|
+
event: T,
|
|
172
|
+
listener: (...args: Events[T]) => void
|
|
173
|
+
): this {
|
|
153
174
|
return super.on(event, listener);
|
|
154
175
|
}
|
|
155
176
|
|
|
156
|
-
once<T extends keyof Events>(
|
|
177
|
+
once<T extends keyof Events>(
|
|
178
|
+
event: T,
|
|
179
|
+
listener: (...args: Events[T]) => void
|
|
180
|
+
): this {
|
|
157
181
|
return super.once(event, listener);
|
|
158
182
|
}
|
|
159
183
|
|
|
@@ -178,7 +202,9 @@ export class Consumer extends EventEmitter {
|
|
|
178
202
|
this.stopped = true;
|
|
179
203
|
}
|
|
180
204
|
|
|
181
|
-
private async handleSqsResponse(
|
|
205
|
+
private async handleSqsResponse(
|
|
206
|
+
response: ReceieveMessageResponse
|
|
207
|
+
): Promise<void> {
|
|
182
208
|
debug('Received SQS response');
|
|
183
209
|
debug(response);
|
|
184
210
|
|
|
@@ -204,7 +230,7 @@ export class Consumer extends EventEmitter {
|
|
|
204
230
|
try {
|
|
205
231
|
if (this.heartbeatInterval) {
|
|
206
232
|
heartbeat = this.startHeartbeat(async () => {
|
|
207
|
-
return this.
|
|
233
|
+
return this.changeVisibilityTimeout(message, this.visibilityTimeout);
|
|
208
234
|
});
|
|
209
235
|
}
|
|
210
236
|
await this.executeHandler(message);
|
|
@@ -214,24 +240,30 @@ export class Consumer extends EventEmitter {
|
|
|
214
240
|
this.emitError(err, message);
|
|
215
241
|
|
|
216
242
|
if (this.terminateVisibilityTimeout) {
|
|
217
|
-
await this.
|
|
243
|
+
await this.changeVisibilityTimeout(message, 0);
|
|
218
244
|
}
|
|
219
245
|
} finally {
|
|
220
246
|
clearInterval(heartbeat);
|
|
221
247
|
}
|
|
222
248
|
}
|
|
223
249
|
|
|
224
|
-
private async receiveMessage(
|
|
250
|
+
private async receiveMessage(
|
|
251
|
+
params: ReceiveMessageRequest
|
|
252
|
+
): Promise<ReceieveMessageResponse> {
|
|
225
253
|
try {
|
|
226
|
-
return await this.sqs
|
|
227
|
-
.receiveMessage(params)
|
|
228
|
-
.promise();
|
|
254
|
+
return await this.sqs.receiveMessage(params).promise();
|
|
229
255
|
} catch (err) {
|
|
230
256
|
throw toSQSError(err, `SQS receive message failed: ${err.message}`);
|
|
231
257
|
}
|
|
232
258
|
}
|
|
233
259
|
|
|
234
260
|
private async deleteMessage(message: SQSMessage): Promise<void> {
|
|
261
|
+
if (!this.shouldDeleteMessages) {
|
|
262
|
+
debug(
|
|
263
|
+
'Skipping message delete since shouldDeleteMessages is set to false'
|
|
264
|
+
);
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
235
267
|
debug('Deleting message %s', message.MessageId);
|
|
236
268
|
|
|
237
269
|
const deleteParams = {
|
|
@@ -240,9 +272,7 @@ export class Consumer extends EventEmitter {
|
|
|
240
272
|
};
|
|
241
273
|
|
|
242
274
|
try {
|
|
243
|
-
await this.sqs
|
|
244
|
-
.deleteMessage(deleteParams)
|
|
245
|
-
.promise();
|
|
275
|
+
await this.sqs.deleteMessage(deleteParams).promise();
|
|
246
276
|
} catch (err) {
|
|
247
277
|
throw toSQSError(err, `SQS delete message failed: ${err.message}`);
|
|
248
278
|
}
|
|
@@ -254,10 +284,7 @@ export class Consumer extends EventEmitter {
|
|
|
254
284
|
try {
|
|
255
285
|
if (this.handleMessageTimeout) {
|
|
256
286
|
[timeout, pending] = createTimeout(this.handleMessageTimeout);
|
|
257
|
-
await Promise.race([
|
|
258
|
-
this.handleMessage(message),
|
|
259
|
-
pending
|
|
260
|
-
]);
|
|
287
|
+
await Promise.race([this.handleMessage(message), pending]);
|
|
261
288
|
} else {
|
|
262
289
|
await this.handleMessage(message);
|
|
263
290
|
}
|
|
@@ -273,9 +300,12 @@ export class Consumer extends EventEmitter {
|
|
|
273
300
|
}
|
|
274
301
|
}
|
|
275
302
|
|
|
276
|
-
private async
|
|
303
|
+
private async changeVisibilityTimeout(
|
|
304
|
+
message: SQSMessage,
|
|
305
|
+
timeout: number
|
|
306
|
+
): Promise<PromiseResult<any, AWSError>> {
|
|
277
307
|
try {
|
|
278
|
-
return this.sqs
|
|
308
|
+
return await this.sqs
|
|
279
309
|
.changeMessageVisibility({
|
|
280
310
|
QueueUrl: this.queueUrl,
|
|
281
311
|
ReceiptHandle: message.ReceiptHandle,
|
|
@@ -283,7 +313,11 @@ export class Consumer extends EventEmitter {
|
|
|
283
313
|
})
|
|
284
314
|
.promise();
|
|
285
315
|
} catch (err) {
|
|
286
|
-
this.emit(
|
|
316
|
+
this.emit(
|
|
317
|
+
'error',
|
|
318
|
+
toSQSError(err, `Error changing visibility timeout: ${err.message}`),
|
|
319
|
+
message
|
|
320
|
+
);
|
|
287
321
|
}
|
|
288
322
|
}
|
|
289
323
|
|
|
@@ -323,9 +357,11 @@ export class Consumer extends EventEmitter {
|
|
|
323
357
|
currentPollingTimeout = this.authenticationErrorTimeout;
|
|
324
358
|
}
|
|
325
359
|
return;
|
|
326
|
-
})
|
|
360
|
+
})
|
|
361
|
+
.then(() => {
|
|
327
362
|
setTimeout(this.poll, currentPollingTimeout);
|
|
328
|
-
})
|
|
363
|
+
})
|
|
364
|
+
.catch((err) => {
|
|
329
365
|
this.emit('error', err);
|
|
330
366
|
});
|
|
331
367
|
}
|
|
@@ -339,7 +375,10 @@ export class Consumer extends EventEmitter {
|
|
|
339
375
|
try {
|
|
340
376
|
if (this.heartbeatInterval) {
|
|
341
377
|
heartbeat = this.startHeartbeat(async () => {
|
|
342
|
-
return this.changeVisabilityTimeoutBatch(
|
|
378
|
+
return this.changeVisabilityTimeoutBatch(
|
|
379
|
+
messages,
|
|
380
|
+
this.visibilityTimeout
|
|
381
|
+
);
|
|
343
382
|
});
|
|
344
383
|
}
|
|
345
384
|
await this.executeBatchHandler(messages);
|
|
@@ -359,7 +398,16 @@ export class Consumer extends EventEmitter {
|
|
|
359
398
|
}
|
|
360
399
|
|
|
361
400
|
private async deleteMessageBatch(messages: SQSMessage[]): Promise<void> {
|
|
362
|
-
|
|
401
|
+
if (!this.shouldDeleteMessages) {
|
|
402
|
+
debug(
|
|
403
|
+
'Skipping message delete since shouldDeleteMessages is set to false'
|
|
404
|
+
);
|
|
405
|
+
return;
|
|
406
|
+
}
|
|
407
|
+
debug(
|
|
408
|
+
'Deleting messages %s',
|
|
409
|
+
messages.map((msg) => msg.MessageId).join(' ,')
|
|
410
|
+
);
|
|
363
411
|
|
|
364
412
|
const deleteParams = {
|
|
365
413
|
QueueUrl: this.queueUrl,
|
|
@@ -370,9 +418,7 @@ export class Consumer extends EventEmitter {
|
|
|
370
418
|
};
|
|
371
419
|
|
|
372
420
|
try {
|
|
373
|
-
await this.sqs
|
|
374
|
-
.deleteMessageBatch(deleteParams)
|
|
375
|
-
.promise();
|
|
421
|
+
await this.sqs.deleteMessageBatch(deleteParams).promise();
|
|
376
422
|
} catch (err) {
|
|
377
423
|
throw toSQSError(err, `SQS delete message failed: ${err.message}`);
|
|
378
424
|
}
|
|
@@ -387,7 +433,10 @@ export class Consumer extends EventEmitter {
|
|
|
387
433
|
}
|
|
388
434
|
}
|
|
389
435
|
|
|
390
|
-
private async changeVisabilityTimeoutBatch(
|
|
436
|
+
private async changeVisabilityTimeoutBatch(
|
|
437
|
+
messages: SQSMessage[],
|
|
438
|
+
timeout: number
|
|
439
|
+
): Promise<PromiseResult<any, AWSError>> {
|
|
391
440
|
const params = {
|
|
392
441
|
QueueUrl: this.queueUrl,
|
|
393
442
|
Entries: messages.map((message) => ({
|
|
@@ -397,11 +446,13 @@ export class Consumer extends EventEmitter {
|
|
|
397
446
|
}))
|
|
398
447
|
};
|
|
399
448
|
try {
|
|
400
|
-
return this.sqs
|
|
401
|
-
.changeMessageVisibilityBatch(params)
|
|
402
|
-
.promise();
|
|
449
|
+
return await this.sqs.changeMessageVisibilityBatch(params).promise();
|
|
403
450
|
} catch (err) {
|
|
404
|
-
this.emit(
|
|
451
|
+
this.emit(
|
|
452
|
+
'error',
|
|
453
|
+
toSQSError(err, `Error changing visibility timeout: ${err.message}`),
|
|
454
|
+
messages
|
|
455
|
+
);
|
|
405
456
|
}
|
|
406
457
|
}
|
|
407
458
|
|