ac-sqs 3.0.0 → 3.1.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/CHANGELOG.md CHANGED
@@ -1,3 +1,22 @@
1
+
2
+ # [3.1.0](https://github.com/admiralcloud/ac-sqs/compare/v3.0.0..v3.1.0) (2025-04-12 08:11:38)
3
+
4
+
5
+ ### Feature
6
+
7
+ * **App:** Add visibilityTimeout management | MP | [ccdd4d0230fc98a5e1aa8531a9939ef2457b614a](https://github.com/admiralcloud/ac-sqs/commit/ccdd4d0230fc98a5e1aa8531a9939ef2457b614a)
8
+ It is now possible to automatically extend visibility for messages. Just set visibilityTimeout in list config
9
+ Related issues: [admiralcloud/ac-sqs#1](https://github.com/admiralcloud/ac-sqs/issues/1) [admiralcloud/ac-api-server#340](https://github.com/admiralcloud/ac-api-server/issues/340)
10
+ ### Documentation
11
+
12
+ * **App:** Added visibilityTimeout management | MP | [4c6e916b0056c894dcac5cb58fa48166de769de4](https://github.com/admiralcloud/ac-sqs/commit/4c6e916b0056c894dcac5cb58fa48166de769de4)
13
+ Added visibilityTimeout management
14
+ Related issues: [admiralcloud/ac-sqs#1](https://github.com/admiralcloud/ac-sqs/issues/1) [admiralcloud/ac-api-server#340](https://github.com/admiralcloud/ac-api-server/issues/340)
15
+ ### Chores
16
+
17
+ * **App:** Updated packages | MP | [c2f533d3bd7bb0d9917d9815e46ef6e8ab5c79d2](https://github.com/admiralcloud/ac-sqs/commit/c2f533d3bd7bb0d9917d9815e46ef6e8ab5c79d2)
18
+ Updated packages
19
+ Related issues: [admiralcloud/ac-sqs#1](https://github.com/admiralcloud/ac-sqs/issues/1) [admiralcloud/ac-api-server#340](https://github.com/admiralcloud/ac-api-server/issues/340)
1
20
  <a name="3.0.0"></a>
2
21
 
3
22
  # [3.0.0](https://github.com/admiralcloud/ac-sqs/compare/v2.0.8..v3.0.0) (2024-10-17 15:51:06)
package/README.md CHANGED
@@ -33,7 +33,7 @@ The ***account*** id of your AWS account. This is required
33
33
  Array of AWS SQS lists that will be used by this function. Every item in the list must be an object with the following properties:
34
34
  + name -> the name of the list in AWS SQS. See below for more info.
35
35
  + batchSize -> number of messages to fetch per call. Max 10, defaults to 1
36
- + visibilityTimeout -> see AWS SQS for details, defaults to 30
36
+ + visibilityTimeout -> see AWS SQS for details, defaults to 30. If set, visibilityTimeout management is activated
37
37
  + waitTime -> see AWS SQS for details, defaults to 20
38
38
  + fifo -> set to true, if this is a fifo list
39
39
  + localPrefix -> set your local prefix. See below for more info
@@ -55,6 +55,9 @@ useS3: {
55
55
  }
56
56
  ```
57
57
 
58
+ **Visibility Timeout Management**
59
+ If you set list config parameter visibilityTimeout, the automatic visibilityTimeout management will be activated. It will make sure that visibilityTimeout for messages is automatically extended.
60
+
58
61
  Make sure your function can read, write and delete messages in the bucket.
59
62
 
60
63
  ## sendSQSMessage
package/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  const _ = require('lodash')
2
2
  const { v4: uuidV4 } = require('uuid')
3
3
 
4
- const { SQSClient, SendMessageCommand, ReceiveMessageCommand, DeleteMessageBatchCommand, GetQueueAttributesCommand } = require('@aws-sdk/client-sqs')
4
+ const { SQSClient, SendMessageCommand, ReceiveMessageCommand, DeleteMessageBatchCommand, GetQueueAttributesCommand, ChangeMessageVisibilityCommand } = require('@aws-sdk/client-sqs')
5
5
  const { S3Client, GetObjectCommand, PutObjectCommand, DeleteObjectsCommand } = require("@aws-sdk/client-s3")
6
6
 
7
7
 
@@ -12,6 +12,7 @@ class ACSQS {
12
12
  this.availableLists = availableLists
13
13
  this.logger = logger
14
14
  this.throwError = throwError
15
+ this.visibilityTimer = {}
15
16
 
16
17
  const awsConfig = {
17
18
  region,
@@ -109,13 +110,71 @@ class ACSQS {
109
110
  }
110
111
  }
111
112
 
113
+ async extendVisibility({ name, message }) {
114
+ const config = _.find(this.availableLists, { name })
115
+ if (!config) {
116
+ this.logger.error('AWS | extendVisibility | configurationMissing | %s', name)
117
+ throw new Error('configurationForListMissing')
118
+ }
119
+
120
+ const visibilityTimeout = _.get(config, 'visibilityTimeout', 15)
121
+ const maxVisibilityExtensions = _.get(config, 'maxVisibilityExtensions', 12) // max number of times the extension can me made (12 x 15s = 3min)
122
+
123
+ const { MessageId: messageId, ReceiptHandle: receiptHandle } = message
124
+
125
+ // Check if we've reached maximum extensions
126
+ if (this.visibilityTimer[messageId] && this.visibilityTimer[messageId].visibilityExtensionCount >= maxVisibilityExtensions) {
127
+ this.logger.warn('ACSQS | extendVisibility | %s | M %s | Max extensions reached | %s | %j', name, messageId, maxVisibilityExtensions, message)
128
+ this.deleteVisibilityTimer({ messageId })
129
+ return
130
+ }
131
+
132
+ // Track extension count
133
+ if (this.visibilityTimer[messageId]) {
134
+ this.visibilityTimer[messageId].visibilityExtensionCount++
135
+ }
136
+
137
+ const sqsParams = {
138
+ QueueUrl: await this.getQueueUrl(config),
139
+ ReceiptHandle: receiptHandle,
140
+ VisibilityTimeout: visibilityTimeout
141
+ }
142
+ const command = new ChangeMessageVisibilityCommand(sqsParams)
143
+ try {
144
+ const response = await this.sqs.send(command)
145
+ if (config.debug) {
146
+ const visibilityExtensionCount = this.visibilityTimer[messageId] ? this.visibilityTimer[messageId].visibilityExtensionCount : 0
147
+ this.logger.debug('ACSQS | extendVisibility | %s | M %s | %ss | %s | %j', name, messageId, visibilityTimeout, visibilityExtensionCount, message)
148
+ }
149
+
150
+ return response
151
+ }
152
+ catch(e) {
153
+ this.logger.error('ACSQS | extendVisibility | %s | %s', name, e?.message)
154
+ this.deleteVisibilityTimer({ messageId })
155
+ if (this.throwError || throwError) throw e
156
+ }
157
+ }
158
+
159
+ deleteVisibilityTimer({ messageId }) {
160
+ if (this.visibilityTimer[messageId]) {
161
+ clearTimeout(this.visibilityTimer[messageId].timer)
162
+ const self = this
163
+ setTimeout(() => {
164
+ delete self.visibilityTimer[messageId]
165
+ }, 1000)
166
+ }
167
+ }
168
+
112
169
  async receiveSQSMessages({ name, throwError }) {
113
170
  const config = _.find(this.availableLists, { name })
114
171
  if (!config) {
115
- this.logger.error('AWS | receiveSQSMessage | configurationMissing | %s', name)
172
+ this.logger.error('ACSQS | receiveSQSMessage | configurationMissing | %s', name)
116
173
  throw new Error('configurationForListMissing')
117
174
  }
118
- let sqsParams = {
175
+ const visibilityTimeout = _.get(config, 'visibilityTimeout') // if set, will activate visibilityTimeout management
176
+
177
+ const sqsParams = {
119
178
  QueueUrl: await this.getQueueUrl(config),
120
179
  MaxNumberOfMessages: _.get(config, 'batchSize', 10),
121
180
  VisibilityTimeout: _.get(config, 'visibilityTimeout', 30),
@@ -126,7 +185,9 @@ class ACSQS {
126
185
  try {
127
186
  const result = await this.sqs.send(command)
128
187
  if (!_.size(result.Messages)) return
129
- const messages = await Promise.all(result.Messages.map(async message => {
188
+
189
+ // Benutze Arrow-Funktion, um `this` beizubehalten
190
+ const messages = await Promise.all(result.Messages.map(async (message) => {
130
191
  if (message.Body.startsWith('s3:')) {
131
192
  const key = message.Body.replace('s3:', '')
132
193
  try {
@@ -135,9 +196,29 @@ class ACSQS {
135
196
  message.s3key = key
136
197
  }
137
198
  catch(e) {
138
- this.logger.error('AWS | receiveSQSMessages | s3KeyInvalid | %s', name, key)
199
+ this.logger.error('ACSQS | receiveSQSMessages | s3KeyInvalid | %s', name, key)
139
200
  }
140
201
  }
202
+
203
+ if (visibilityTimeout > 0) {
204
+ // start visibility timer that automatically extends visibility of the message if required
205
+ const { MessageId: messageId } = message
206
+ const timeoutMs = Math.floor(visibilityTimeout * 0.8 * 1000)
207
+ const self = this // `this` als lokale Variable speichern
208
+
209
+ this.visibilityTimer[messageId] = {
210
+ // Arrow-Funktion für setInterval damit `this` erhalten bleibt,
211
+ // oder verwende die lokale Variable `self`
212
+ timer: setInterval(() => {
213
+ this.extendVisibility({ name, message })
214
+ .catch(e => {
215
+ this.logger.error('ACSQS | AutoExtendVisibility | Failed %s', e.message)
216
+ })
217
+ }, timeoutMs),
218
+ visibilityExtensionCount: 0
219
+ }
220
+ }
221
+
141
222
  return message
142
223
  }))
143
224
  return messages
@@ -156,6 +237,11 @@ class ACSQS {
156
237
  throw new Error('configurationForListMissing')
157
238
  }
158
239
 
240
+ if (!_.size(items)) {
241
+ this.logger.error('AWS | deleteSQSMessage | %s | noItemsToDelete', name)
242
+ return
243
+ }
244
+
159
245
  const entries = []
160
246
  const s3keys = []
161
247
  for (const item of items) {
@@ -163,8 +249,13 @@ class ACSQS {
163
249
  if (item.s3key) {
164
250
  s3keys.push({ Key: item.s3key })
165
251
  }
252
+ const messageId = item.Id
253
+ if (this.visibilityTimer[messageId]) {
254
+ this.deleteVisibilityTimer({ messageId })
255
+ }
166
256
  }
167
257
 
258
+
168
259
  let sqsParams = {
169
260
  QueueUrl: await this.getQueueUrl(config),
170
261
  Entries: entries
package/package.json CHANGED
@@ -3,18 +3,18 @@
3
3
  "author": "Mark Poepping (https://www.admiralcloud.com)",
4
4
  "license": "MIT",
5
5
  "repository": "admiralcloud/ac-sqs",
6
- "version": "3.0.0",
6
+ "version": "3.1.0",
7
7
  "dependencies": {
8
- "@aws-sdk/client-s3": "^3.673.0",
9
- "@aws-sdk/client-sqs": "^3.670.0",
8
+ "@aws-sdk/client-s3": "^3.787.0",
9
+ "@aws-sdk/client-sqs": "^3.787.0",
10
10
  "lodash": "^4.17.21",
11
- "uuid": "^10.0.0"
11
+ "uuid": "^11.1.0"
12
12
  },
13
13
  "devDependencies": {
14
- "ac-semantic-release": "^0.4.3",
14
+ "ac-semantic-release": "^0.4.5",
15
15
  "chai": "^4.5.0",
16
- "eslint": "^9.12.0",
17
- "mocha": "^10.7.3"
16
+ "eslint": "^9.24.0",
17
+ "mocha": "^11.1.0"
18
18
  },
19
19
  "scripts": {
20
20
  "test": "mocha --reporter spec"