consumer-pgmq 2.0.1 → 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.
@@ -1,6 +1,5 @@
1
1
  import Consumer from '../src/consumer'
2
2
  import { Message, QueueDriver, Options } from '../src/type'
3
- import timersPromises from 'node:timers/promises'
4
3
 
5
4
  describe('Consumer', () => {
6
5
  let queueDriver: jest.Mocked<QueueDriver>
@@ -18,6 +17,9 @@ describe('Consumer', () => {
18
17
  get: jest.fn(),
19
18
  pop: jest.fn(),
20
19
  delete: jest.fn(),
20
+ send: jest.fn(),
21
+ allocateConsumer: jest.fn(),
22
+ freeConsumer: jest.fn()
21
23
  }
22
24
  jest.useFakeTimers();
23
25
  })
@@ -28,6 +30,165 @@ describe('Consumer', () => {
28
30
  })
29
31
 
30
32
 
33
+ it('Should throw error if set dead letter queue and no set total retries before send to dlq', async () => {
34
+ try {
35
+ queueDriver.get.mockResolvedValueOnce({ data: [message], error: null })
36
+ queueDriver.delete.mockResolvedValueOnce({ error: null })
37
+ queueDriver.get.mockResolvedValueOnce({ data: [], error: null })
38
+
39
+ const handler = jest.fn(async () => { })
40
+ const consumer = new Consumer(
41
+ {
42
+ queueName: 'q',
43
+ consumeType: 'read',
44
+ visibilityTime: 1,
45
+ poolSize: 1,
46
+ timeMsWaitBeforeNextPolling: 1,
47
+ enabledPolling: true,
48
+ queueNameDlq: 'q_dlq',
49
+ },
50
+ handler,
51
+ queueDriver
52
+ )
53
+
54
+ const onFinish = jest.fn()
55
+ consumer.on('finish', onFinish)
56
+ await consumer.start()
57
+ } catch (error: any) {
58
+ expect(error).toBeInstanceOf(Error)
59
+ expect(error.message).toBe('The option totalRetriesBeforeSendToDlq is required when queueNameDlq is set')
60
+ }
61
+ })
62
+
63
+
64
+ it('Should send message to dlq if read count is greater than total retries before send to dlq', async () => {
65
+ const messageToSendDlq = { ...message }
66
+ messageToSendDlq.read_ct = 3
67
+ messageToSendDlq.msg_id = 2
68
+ queueDriver.get.mockResolvedValueOnce({ data: [messageToSendDlq], error: null })
69
+ queueDriver.delete.mockResolvedValueOnce({ error: null })
70
+ queueDriver.get.mockResolvedValueOnce({ data: [], error: null })
71
+ queueDriver.send.mockResolvedValueOnce({ error: null })
72
+
73
+ const handler = jest.fn(async () => { })
74
+ const consumer = new Consumer(
75
+ {
76
+ queueName: 'q',
77
+ consumeType: 'read',
78
+ visibilityTime: 1,
79
+ poolSize: 1,
80
+ timeMsWaitBeforeNextPolling: 1,
81
+ enabledPolling: true,
82
+ queueNameDlq: 'q_dlq',
83
+ totalRetriesBeforeSendToDlq: 2
84
+ },
85
+ handler,
86
+ queueDriver
87
+ )
88
+
89
+ const onFinish = jest.fn()
90
+ consumer.on('finish', onFinish)
91
+ await consumer.start()
92
+
93
+ expect(handler).toHaveBeenCalledTimes(0)
94
+ expect(onFinish).toHaveBeenCalledTimes(0)
95
+ expect(queueDriver.delete).toHaveBeenCalledTimes(1)
96
+ expect(queueDriver.send).toHaveBeenCalledTimes(1)
97
+ expect(queueDriver.send).toHaveBeenCalledWith(
98
+ 'q_dlq', messageToSendDlq.message, expect.any(AbortSignal)
99
+ )
100
+ })
101
+
102
+ it('Should send 2 messages to dlq if read count is greater than total retries before send to dlq', async () => {
103
+ const messageToSendDlq = { ...message }
104
+ messageToSendDlq.read_ct = 3
105
+ messageToSendDlq.msg_id = 2
106
+ queueDriver.get.mockResolvedValueOnce({
107
+ data: [
108
+ messageToSendDlq, messageToSendDlq
109
+ ], error: null
110
+ })
111
+ queueDriver.delete.mockResolvedValueOnce({ error: null })
112
+ queueDriver.get.mockResolvedValueOnce({ data: [], error: null })
113
+ queueDriver.send.mockResolvedValue({ error: null })
114
+
115
+ const handler = jest.fn(async () => { })
116
+ const consumer = new Consumer(
117
+ {
118
+ queueName: 'q',
119
+ consumeType: 'read',
120
+ visibilityTime: 1,
121
+ poolSize: 2,
122
+ timeMsWaitBeforeNextPolling: 1,
123
+ enabledPolling: true,
124
+ queueNameDlq: 'q_dlq',
125
+ totalRetriesBeforeSendToDlq: 2
126
+ },
127
+ handler,
128
+ queueDriver
129
+ )
130
+
131
+ const onFinish = jest.fn()
132
+ consumer.on('finish', onFinish)
133
+ await consumer.start()
134
+
135
+ expect(handler).toHaveBeenCalledTimes(0)
136
+ expect(onFinish).toHaveBeenCalledTimes(0)
137
+ expect(queueDriver.delete).toHaveBeenCalledTimes(2)
138
+ expect(queueDriver.send).toHaveBeenCalledTimes(2)
139
+ expect(queueDriver.send).toHaveBeenCalledWith(
140
+ 'q_dlq', messageToSendDlq.message, expect.any(AbortSignal)
141
+ )
142
+ })
143
+
144
+
145
+ it('Should send only 1 message to dlq if read count is greater than total retries before send to dlq', async () => {
146
+ const messageToSendDlq = { ...message }
147
+ messageToSendDlq.read_ct = 3
148
+ messageToSendDlq.msg_id = 2
149
+
150
+ const messageToSendDlq2 = { ...message }
151
+ messageToSendDlq2.read_ct = 1
152
+ messageToSendDlq2.msg_id = 3
153
+ queueDriver.get.mockResolvedValueOnce({
154
+ data: [
155
+ messageToSendDlq, messageToSendDlq2
156
+ ], error: null
157
+ })
158
+ queueDriver.delete.mockResolvedValue({ error: null })
159
+ queueDriver.get.mockResolvedValueOnce({ data: [], error: null })
160
+ queueDriver.send.mockResolvedValue({ error: null })
161
+
162
+ const handler = jest.fn(async () => {
163
+ return Promise.resolve()
164
+ })
165
+ const consumer = new Consumer(
166
+ {
167
+ queueName: 'q',
168
+ consumeType: 'read',
169
+ visibilityTime: 1,
170
+ poolSize: 2,
171
+ timeMsWaitBeforeNextPolling: 1,
172
+ enabledPolling: true,
173
+ queueNameDlq: 'q_dlq',
174
+ totalRetriesBeforeSendToDlq: 2
175
+ },
176
+ handler,
177
+ queueDriver
178
+ )
179
+
180
+ const onFinish = jest.fn()
181
+ consumer.on('finish', onFinish)
182
+ await consumer.start()
183
+
184
+ expect(handler).toHaveBeenCalledTimes(1)
185
+ expect(onFinish).toHaveBeenCalledTimes(1)
186
+ expect(queueDriver.delete).toHaveBeenCalledTimes(2)
187
+ expect(queueDriver.send).toHaveBeenCalledTimes(1)
188
+ expect(queueDriver.send).toHaveBeenCalledWith(
189
+ 'q_dlq', messageToSendDlq.message, expect.any(AbortSignal)
190
+ )
191
+ })
31
192
 
32
193
  it('Should not process message if read method does not return any message second polling', async () => {
33
194
  queueDriver.get.mockResolvedValueOnce({ data: [message], error: null })
@@ -41,7 +202,8 @@ describe('Consumer', () => {
41
202
  consumeType: 'read',
42
203
  visibilityTime: 1,
43
204
  poolSize: 1,
44
- timeMsWaitBeforeNextPolling: 1
205
+ timeMsWaitBeforeNextPolling: 1,
206
+ enabledPolling: true
45
207
  },
46
208
  handler,
47
209
  queueDriver
@@ -69,7 +231,8 @@ describe('Consumer', () => {
69
231
  consumeType: 'pop',
70
232
  visibilityTime: 1,
71
233
  poolSize: 1,
72
- timeMsWaitBeforeNextPolling: 1
234
+ timeMsWaitBeforeNextPolling: 1,
235
+ enabledPolling: true
73
236
  },
74
237
  handler,
75
238
  queueDriver
@@ -95,7 +258,8 @@ describe('Consumer', () => {
95
258
  consumeType: 'pop',
96
259
  visibilityTime: 1,
97
260
  poolSize: 1,
98
- timeMsWaitBeforeNextPolling: 1
261
+ timeMsWaitBeforeNextPolling: 1,
262
+ enabledPolling: true
99
263
  },
100
264
  handler,
101
265
  queueDriver
@@ -121,7 +285,8 @@ describe('Consumer', () => {
121
285
  consumeType: 'read',
122
286
  visibilityTime: 1,
123
287
  poolSize: 1,
124
- timeMsWaitBeforeNextPolling: 1
288
+ timeMsWaitBeforeNextPolling: 1,
289
+ enabledPolling: true
125
290
  },
126
291
  handler,
127
292
  queueDriver
@@ -150,7 +315,8 @@ describe('Consumer', () => {
150
315
  consumeType: 'read',
151
316
  visibilityTime: 1,
152
317
  poolSize: 1,
153
- timeMsWaitBeforeNextPolling: 1
318
+ timeMsWaitBeforeNextPolling: 1,
319
+ enabledPolling: true
154
320
  },
155
321
  handler,
156
322
  queueDriver
@@ -179,7 +345,8 @@ describe('Consumer', () => {
179
345
  consumeType: 'read',
180
346
  visibilityTime: 1,
181
347
  poolSize: 4,
182
- timeMsWaitBeforeNextPolling: 1
348
+ timeMsWaitBeforeNextPolling: 1,
349
+ enabledPolling: true
183
350
  },
184
351
  handler,
185
352
  queueDriver
@@ -230,8 +397,35 @@ describe('Consumer', () => {
230
397
 
231
398
  await consumer.start()
232
399
 
400
+ expect(queueDriver.allocateConsumer).toHaveBeenCalledTimes(0)
233
401
  expect(onError).toHaveBeenCalled()
234
402
  expect((onError.mock.calls[0][0] as Error).message)
235
403
  .toBe('visibilityTime is required for read')
236
404
  })
405
+
406
+
407
+ it('Should call allocateConsumer when option enableControlConsumer is true', async () => {
408
+ queueDriver.allocateConsumer.mockResolvedValue({ id: '1' })
409
+ const consumer = new Consumer(
410
+ { queueName: 'q', consumeType: 'read', enableControlConsumer: true } as Options,
411
+ async () => { },
412
+ queueDriver
413
+ )
414
+
415
+ await consumer.start()
416
+
417
+ expect(queueDriver.allocateConsumer).toHaveBeenCalled()
418
+ })
419
+
420
+
421
+ it('Should call freeConsumer when option enableControlConsumer is true and process exit', async () => {
422
+ queueDriver.allocateConsumer.mockResolvedValue({ id: '1' })
423
+ const consumer = new Consumer(
424
+ { queueName: 'q', consumeType: 'read', enableControlConsumer: true } as Options,
425
+ async () => { },
426
+ queueDriver
427
+ )
428
+
429
+ await consumer.start()
430
+ })
237
431
  })