sqs-consumer 6.0.2 → 6.2.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/src/errors.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import { AWSError } from './types';
2
+
1
3
  class SQSError extends Error {
2
4
  code: string;
3
5
  statusCode: number;
@@ -20,4 +22,37 @@ class TimeoutError extends Error {
20
22
  }
21
23
  }
22
24
 
23
- export { SQSError, TimeoutError };
25
+ /**
26
+ * Checks if the error provided should be treated as a connection error.
27
+ * @param err The error that was received.
28
+ */
29
+ function isConnectionError(err: Error): boolean {
30
+ if (err instanceof SQSError) {
31
+ return (
32
+ err.statusCode === 403 ||
33
+ err.code === 'CredentialsError' ||
34
+ err.code === 'UnknownEndpoint' ||
35
+ err.code === 'AWS.SimpleQueueService.NonExistentQueue'
36
+ );
37
+ }
38
+ return false;
39
+ }
40
+
41
+ /**
42
+ * Formats an AWSError the the SQSError type.
43
+ * @param err The error object that was received.
44
+ * @param message The message that the error occurred on.
45
+ */
46
+ function toSQSError(err: AWSError, message: string): SQSError {
47
+ const sqsError = new SQSError(message);
48
+ sqsError.code = err.name;
49
+ sqsError.statusCode = err.$metadata?.httpStatusCode;
50
+ sqsError.retryable = err.$retryable?.throttling;
51
+ sqsError.service = err.$service;
52
+ sqsError.fault = err.$fault;
53
+ sqsError.time = new Date();
54
+
55
+ return sqsError;
56
+ }
57
+
58
+ export { SQSError, TimeoutError, isConnectionError, toSQSError };
package/src/index.ts CHANGED
@@ -1 +1,2 @@
1
- export { Consumer, ConsumerOptions } from './consumer';
1
+ export { Consumer } from './consumer';
2
+ export * from './types';
package/src/types.ts CHANGED
@@ -1,3 +1,181 @@
1
+ import { SQSClient, Message } from '@aws-sdk/client-sqs';
2
+ import { EventEmitter } from 'events';
3
+
4
+ export interface ConsumerOptions {
5
+ /**
6
+ * The SQS queue URL.
7
+ */
8
+ queueUrl: string;
9
+ /**
10
+ * List of queue attributes to retrieve (i.e.
11
+ * `['All', 'ApproximateFirstReceiveTimestamp', 'ApproximateReceiveCount']`).
12
+ * @defaultvalue `[]`
13
+ */
14
+ attributeNames?: string[];
15
+ /**
16
+ * List of message attributes to retrieve (i.e. `['name', 'address']`).
17
+ * @defaultvalue `[]`
18
+ */
19
+ messageAttributeNames?: string[];
20
+ /** @hidden */
21
+ stopped?: boolean;
22
+ /**
23
+ * The number of messages to request from SQS when polling (default `1`).
24
+ *
25
+ * This cannot be higher than the
26
+ * [AWS limit of 10](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/quotas-messages.html).
27
+ * @defaultvalue `1`
28
+ */
29
+ batchSize?: number;
30
+ /**
31
+ * The duration (in seconds) that the received messages are hidden from subsequent
32
+ * retrieve requests after being retrieved by a ReceiveMessage request.
33
+ */
34
+ visibilityTimeout?: number;
35
+ /**
36
+ * The duration (in seconds) for which the call will wait for a message to arrive in
37
+ * the queue before returning.
38
+ * @defaultvalue `20`
39
+ */
40
+ waitTimeSeconds?: number;
41
+ /**
42
+ * The duration (in milliseconds) to wait before retrying after an authentication error.
43
+ * @defaultvalue `10000`
44
+ */
45
+ authenticationErrorTimeout?: number;
46
+ /**
47
+ * The duration (in milliseconds) to wait before repolling the queue.
48
+ * @defaultvalue `0`
49
+ */
50
+ pollingWaitTimeMs?: number;
51
+ /**
52
+ * If true, sets the message visibility timeout to 0 after a `processing_error`.
53
+ * @defaultvalue `false`
54
+ */
55
+ terminateVisibilityTimeout?: boolean;
56
+ /**
57
+ * The interval (in seconds) between requests to extend the message visibility timeout.
58
+ *
59
+ * On each heartbeat the visibility is extended by adding `visibilityTimeout` to
60
+ * the number of seconds since the start of the handler function.
61
+ *
62
+ * This value must less than `visibilityTimeout`.
63
+ */
64
+ heartbeatInterval?: number;
65
+ /**
66
+ * An optional [SQS Client](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-sqs/classes/sqsclient.html)
67
+ * object to use if you need to configure the client manually.
68
+ */
69
+ sqs?: SQSClient;
70
+ /**
71
+ * The AWS region.
72
+ * @defaultValue `eu-west-1`
73
+ */
74
+ region?: string;
75
+ /**
76
+ * Time in ms to wait for `handleMessage` to process a message before timing out.
77
+ *
78
+ * Emits `timeout_error` on timeout. By default, if `handleMessage` times out,
79
+ * the unprocessed message returns to the end of the queue.
80
+ */
81
+ handleMessageTimeout?: number;
82
+ /**
83
+ * Default to `true`, if you don't want the package to delete messages from sqs
84
+ * set this to `false`.
85
+ * @defaultvalue `true`
86
+ */
87
+ shouldDeleteMessages?: boolean;
88
+ /**
89
+ * An `async` function (or function that returns a `Promise`) to be called whenever
90
+ * a message is received.
91
+ *
92
+ * In the case that you need to acknowledge the message, return an object containing
93
+ * the MessageId that you'd like to acknowledge.
94
+ */
95
+ handleMessage?(message: Message): Promise<Message | void>;
96
+ /**
97
+ * An `async` function (or function that returns a `Promise`) to be called whenever
98
+ * a batch of messages is received. Similar to `handleMessage` but will receive the
99
+ * list of messages, not each message individually.
100
+ *
101
+ * **If both are set, `handleMessageBatch` overrides `handleMessage`**.
102
+ *
103
+ * In the case that you need to ack only some of the messages, return an array with
104
+ * the successful messages only.
105
+ */
106
+ handleMessageBatch?(messages: Message[]): Promise<Message[] | void>;
107
+ }
108
+
109
+ export interface Events {
110
+ /**
111
+ * Fired after one batch of items (up to `batchSize`) has been successfully processed.
112
+ */
113
+ response_processed: [];
114
+ /**
115
+ * Fired when the queue is empty (All messages have been consumed).
116
+ */
117
+ empty: [];
118
+ /**
119
+ * Fired when a message is received.
120
+ */
121
+ message_received: [Message];
122
+ /**
123
+ * Fired when a message is successfully processed and removed from the queue.
124
+ */
125
+ message_processed: [Message];
126
+ /**
127
+ * Fired when an error occurs interacting with the queue.
128
+ *
129
+ * If the error correlates to a message, that message is included in Params
130
+ */
131
+ error: [Error, void | Message | Message[]];
132
+ /**
133
+ * Fired when `handleMessageTimeout` is supplied as an option and if
134
+ * `handleMessage` times out.
135
+ */
136
+ timeout_error: [Error, Message];
137
+ /**
138
+ * Fired when an error occurs processing the message.
139
+ */
140
+ processing_error: [Error, Message];
141
+ /**
142
+ * Fired when the consumer finally stops its work.
143
+ */
144
+ stopped: [];
145
+ }
146
+
147
+ export class TypedEventEmitter extends EventEmitter {
148
+ /**
149
+ * Trigger a listener on all emitted events
150
+ * @param event The name of the event to listen to
151
+ * @param listener A function to trigger when the event is emitted
152
+ */
153
+ on<E extends keyof Events>(
154
+ event: E,
155
+ listener: (...args: Events[E]) => void
156
+ ): this {
157
+ return super.on(event, listener);
158
+ }
159
+ /**
160
+ * Trigger a listener only once for an emitted event
161
+ * @param event The name of the event to listen to
162
+ * @param listener A function to trigger when the event is emitted
163
+ */
164
+ once<E extends keyof Events>(
165
+ event: E,
166
+ listener: (...args: Events[E]) => void
167
+ ): this {
168
+ return super.on(event, listener);
169
+ }
170
+ /**
171
+ * Emits an event with the provided arguments
172
+ * @param event The name of the event to emit
173
+ */
174
+ emit<E extends keyof Events>(event: E, ...args: Events[E]): boolean {
175
+ return super.emit(event, ...args);
176
+ }
177
+ }
178
+
1
179
  export type AWSError = {
2
180
  /**
3
181
  * Name, eg. ConditionalCheckFailedException
@@ -0,0 +1,45 @@
1
+ import { ReceiveMessageCommandOutput } from '@aws-sdk/client-sqs';
2
+
3
+ import { ConsumerOptions } from './types';
4
+
5
+ const requiredOptions = [
6
+ 'queueUrl',
7
+ // only one of handleMessage / handleMessagesBatch is required
8
+ 'handleMessage|handleMessageBatch'
9
+ ];
10
+
11
+ /**
12
+ * Ensure that the required options have been set.
13
+ * @param options The options that have been set by the application.
14
+ */
15
+ function assertOptions(options: ConsumerOptions): void {
16
+ requiredOptions.forEach((option) => {
17
+ const possibilities = option.split('|');
18
+ if (!possibilities.find((p) => options[p])) {
19
+ throw new Error(
20
+ `Missing SQS consumer option [ ${possibilities.join(' or ')} ].`
21
+ );
22
+ }
23
+ });
24
+
25
+ if (options.batchSize > 10 || options.batchSize < 1) {
26
+ throw new Error('SQS batchSize option must be between 1 and 10.');
27
+ }
28
+
29
+ if (
30
+ options.heartbeatInterval &&
31
+ !(options.heartbeatInterval < options.visibilityTimeout)
32
+ ) {
33
+ throw new Error('heartbeatInterval must be less than visibilityTimeout.');
34
+ }
35
+ }
36
+
37
+ /**
38
+ * Determine if the response from SQS has messages in it.
39
+ * @param response The response from SQS.
40
+ */
41
+ function hasMessages(response: ReceiveMessageCommandOutput): boolean {
42
+ return response.Messages && response.Messages.length > 0;
43
+ }
44
+
45
+ export { hasMessages, assertOptions };
package/typedoc.json ADDED
@@ -0,0 +1,13 @@
1
+ {
2
+ "$schema": "https://typedoc.org/schema.json",
3
+ "sort": ["kind", "instance-first", "required-first", "alphabetical"],
4
+ "treatWarningsAsErrors": false,
5
+ "searchInComments": true,
6
+ "entryPoints": ["./src/index.ts"],
7
+ "out": "public",
8
+ "name": "SQS Consumer",
9
+ "hideGenerator": true,
10
+ "navigationLinks": {
11
+ "GitHub": "https://github.com/bbc/sqs-consumer"
12
+ }
13
+ }
@@ -1,27 +0,0 @@
1
- ---
2
- name: Bug report
3
- about: Create a report to help us improve
4
- title: ''
5
- labels: bug
6
- assignees: ''
7
- ---
8
-
9
- **Describe the bug**
10
- A clear and concise description of what the bug is.
11
-
12
- **To Reproduce**
13
- Steps to reproduce the behaviour:
14
-
15
- 1. Go to '...'
16
- 2. Select '....'
17
- 3. Scroll down to '....'
18
- 4. See error
19
-
20
- **Expected behaviour**
21
- A clear and concise description of what you expected to happen.
22
-
23
- **screenshots**
24
- If applicable, add screenshots to help explain your problem.
25
-
26
- **Additional context**
27
- Add any other context about the problem here, such as specific device information.
@@ -1,19 +0,0 @@
1
- ---
2
- name: Feature request
3
- about: Suggest an idea for this project
4
- title: ''
5
- labels: feature-request
6
- assignees: ''
7
- ---
8
-
9
- **The problem**
10
- A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
11
-
12
- **Suggested solution**
13
- A clear and concise description of what you want to happen.
14
-
15
- **Alternatives considered**
16
- A clear and concise description of any alternative solutions or features you've considered.
17
-
18
- **Additional context**
19
- Add any other context or screenshots about the feature request here.
@@ -1,16 +0,0 @@
1
- ---
2
- name: Technical question
3
- about: Want to ask a technical question about the project
4
- title: ''
5
- labels: question
6
- assignees: ''
7
- ---
8
-
9
- **Question**
10
- A clear technical question could be asked here.
11
-
12
- **screenshots**
13
- If applicable, add screenshots to help explain your question.
14
-
15
- **Additional context**
16
- Add any other context about the question here, such as specific device information, technology choice etc.