queen-mq 0.2.23 → 0.3.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/README.md +162 -136
- package/client-js/client-v2/LOGGING.md +240 -0
- package/client-js/client-v2/Queen.js +389 -0
- package/client-js/client-v2/README.md +1883 -0
- package/client-js/client-v2/buffer/BufferManager.js +215 -0
- package/client-js/client-v2/buffer/MessageBuffer.js +132 -0
- package/client-js/client-v2/builders/QueueBuilder.js +724 -0
- package/client-js/client-v2/builders/TransactionBuilder.js +110 -0
- package/client-js/client-v2/consumer/ConsumerManager.js +390 -0
- package/client-js/client-v2/http/HttpClient.js +215 -0
- package/client-js/client-v2/http/LoadBalancer.js +50 -0
- package/client-js/client-v2/index.js +7 -0
- package/client-js/client-v2/utils/defaults.js +54 -0
- package/client-js/client-v2/utils/logger.js +54 -0
- package/client-js/client-v2/utils/validation.js +31 -0
- package/client-js/test-v2/AI_TEST_SUMMARY.md +226 -0
- package/client-js/test-v2/GETTING_STARTED.md +154 -0
- package/client-js/test-v2/ai_buffering.js +194 -0
- package/client-js/test-v2/ai_error_handling.js +223 -0
- package/client-js/test-v2/ai_lease_renewal.js +206 -0
- package/client-js/test-v2/ai_mixed_scenarios.js +278 -0
- package/client-js/test-v2/ai_priority.js +169 -0
- package/client-js/test-v2/ai_resources.js +217 -0
- package/client-js/test-v2/ai_ttl_retention.js +170 -0
- package/client-js/test-v2/complete.js +59 -0
- package/client-js/test-v2/consume.js +655 -0
- package/client-js/test-v2/dlq.js +82 -0
- package/client-js/test-v2/load.js +177 -0
- package/client-js/test-v2/pop.js +114 -0
- package/client-js/test-v2/push.js +333 -0
- package/client-js/test-v2/queue.js +39 -0
- package/client-js/test-v2/run.js +187 -0
- package/client-js/test-v2/subscription.js +354 -0
- package/client-js/test-v2/transaction.js +443 -0
- package/package.json +1 -1
|
@@ -0,0 +1,443 @@
|
|
|
1
|
+
export async function transactionBasicPushAck(client) {
|
|
2
|
+
const queueA = await client.queue('test-queue-v2-txn-basic-a').create()
|
|
3
|
+
const queueB = await client.queue('test-queue-v2-txn-basic-b').create()
|
|
4
|
+
if (!queueA.configured || !queueB.configured) {
|
|
5
|
+
return { success: false, message: 'Queues not created' }
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
// Push a message to queue A
|
|
9
|
+
await client.queue('test-queue-v2-txn-basic-a').push([{ data: { value: 1 } }])
|
|
10
|
+
|
|
11
|
+
// Pop from A and push to B in a transaction
|
|
12
|
+
const messages = await client.queue('test-queue-v2-txn-basic-a').batch(1).wait(false).pop()
|
|
13
|
+
if (messages.length === 0) {
|
|
14
|
+
return { success: false, message: 'No message to consume' }
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
await client
|
|
18
|
+
.transaction()
|
|
19
|
+
.queue('test-queue-v2-txn-basic-b')
|
|
20
|
+
.push([{ data: { value: messages[0].data.value + 1 } }])
|
|
21
|
+
.ack(messages[0])
|
|
22
|
+
.commit()
|
|
23
|
+
|
|
24
|
+
// Verify message moved to B
|
|
25
|
+
const resultB = await client.queue('test-queue-v2-txn-basic-b').batch(1).wait(false).pop()
|
|
26
|
+
const resultA = await client.queue('test-queue-v2-txn-basic-a').batch(1).wait(false).pop()
|
|
27
|
+
|
|
28
|
+
return {
|
|
29
|
+
success: resultB.length === 1 && resultA.length === 0 && resultB[0].data.value === 2,
|
|
30
|
+
message: 'Basic transaction push+ack completed'
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export async function transactionMultiplePushes(client) {
|
|
35
|
+
const queueA = await client.queue('test-queue-v2-txn-multi-a').create()
|
|
36
|
+
const queueB = await client.queue('test-queue-v2-txn-multi-b').create()
|
|
37
|
+
const queueC = await client.queue('test-queue-v2-txn-multi-c').create()
|
|
38
|
+
if (!queueA.configured || !queueB.configured || !queueC.configured) {
|
|
39
|
+
return { success: false, message: 'Queues not created' }
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Push to queue A
|
|
43
|
+
await client.queue('test-queue-v2-txn-multi-a').push([{ data: { id: 'source' } }])
|
|
44
|
+
|
|
45
|
+
// Pop from A
|
|
46
|
+
const messages = await client.queue('test-queue-v2-txn-multi-a').batch(1).wait(false).pop()
|
|
47
|
+
if (messages.length === 0) {
|
|
48
|
+
return { success: false, message: 'No message to consume' }
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Transaction: Push to B and C, ack from A
|
|
52
|
+
await client
|
|
53
|
+
.transaction()
|
|
54
|
+
.queue('test-queue-v2-txn-multi-b')
|
|
55
|
+
.push([{ data: { id: 'b', source: messages[0].data.id } }])
|
|
56
|
+
.queue('test-queue-v2-txn-multi-c')
|
|
57
|
+
.push([{ data: { id: 'c', source: messages[0].data.id } }])
|
|
58
|
+
.ack(messages[0])
|
|
59
|
+
.commit()
|
|
60
|
+
|
|
61
|
+
// Verify messages in B and C
|
|
62
|
+
const resultB = await client.queue('test-queue-v2-txn-multi-b').batch(1).wait(false).pop()
|
|
63
|
+
const resultC = await client.queue('test-queue-v2-txn-multi-c').batch(1).wait(false).pop()
|
|
64
|
+
const resultA = await client.queue('test-queue-v2-txn-multi-a').batch(1).wait(false).pop()
|
|
65
|
+
|
|
66
|
+
return {
|
|
67
|
+
success: resultB.length === 1 && resultC.length === 1 && resultA.length === 0,
|
|
68
|
+
message: 'Multiple pushes in transaction completed'
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export async function transactionMultipleAcks(client) {
|
|
73
|
+
const queueA = await client.queue('test-queue-v2-txn-multi-ack-a').create()
|
|
74
|
+
const queueB = await client.queue('test-queue-v2-txn-multi-ack-b').create()
|
|
75
|
+
if (!queueA.configured || !queueB.configured) {
|
|
76
|
+
return { success: false, message: 'Queues not created' }
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Push 3 messages to queue A
|
|
80
|
+
await client.queue('test-queue-v2-txn-multi-ack-a').push([
|
|
81
|
+
{ data: { value: 1 } },
|
|
82
|
+
{ data: { value: 2 } },
|
|
83
|
+
{ data: { value: 3 } }
|
|
84
|
+
])
|
|
85
|
+
|
|
86
|
+
// Pop 3 messages from A
|
|
87
|
+
const messages = await client.queue('test-queue-v2-txn-multi-ack-a').batch(3).wait(false).pop()
|
|
88
|
+
if (messages.length !== 3) {
|
|
89
|
+
return { success: false, message: `Expected 3 messages, got ${messages.length}` }
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Transaction: Ack all 3, push summary to B
|
|
93
|
+
const sum = messages.reduce((acc, msg) => acc + msg.data.value, 0)
|
|
94
|
+
await client
|
|
95
|
+
.transaction()
|
|
96
|
+
.ack(messages[0])
|
|
97
|
+
.ack(messages[1])
|
|
98
|
+
.ack(messages[2])
|
|
99
|
+
.queue('test-queue-v2-txn-multi-ack-b')
|
|
100
|
+
.push([{ data: { sum } }])
|
|
101
|
+
.commit()
|
|
102
|
+
|
|
103
|
+
// Verify
|
|
104
|
+
const resultA = await client.queue('test-queue-v2-txn-multi-ack-a').batch(3).wait(false).pop()
|
|
105
|
+
const resultB = await client.queue('test-queue-v2-txn-multi-ack-b').batch(1).wait(false).pop()
|
|
106
|
+
|
|
107
|
+
return {
|
|
108
|
+
success: resultA.length === 0 && resultB.length === 1 && resultB[0].data.sum === 6,
|
|
109
|
+
message: 'Multiple acks in transaction completed'
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export async function transactionAckWithStatus(client) {
|
|
114
|
+
const queueA = await client.queue('test-queue-v2-txn-ack-status-a').create()
|
|
115
|
+
const queueB = await client.queue('test-queue-v2-txn-ack-status-b').create()
|
|
116
|
+
if (!queueA.configured || !queueB.configured) {
|
|
117
|
+
return { success: false, message: 'Queues not created' }
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Push a message
|
|
121
|
+
await client.queue('test-queue-v2-txn-ack-status-a').push([{ data: { value: 1 } }])
|
|
122
|
+
|
|
123
|
+
// Pop the message
|
|
124
|
+
const messages = await client.queue('test-queue-v2-txn-ack-status-a').batch(1).wait(false).pop()
|
|
125
|
+
if (messages.length === 0) {
|
|
126
|
+
return { success: false, message: 'No message to consume' }
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// ACK with custom status in a transaction
|
|
130
|
+
await client
|
|
131
|
+
.transaction()
|
|
132
|
+
.ack(messages[0], 'failed') // Ack with 'failed' status
|
|
133
|
+
.queue('test-queue-v2-txn-ack-status-b')
|
|
134
|
+
.push([{ data: { processed: true } }])
|
|
135
|
+
.commit()
|
|
136
|
+
|
|
137
|
+
// Verify message was acked and new message was pushed
|
|
138
|
+
const resultA = await client.queue('test-queue-v2-txn-ack-status-a').batch(1).wait(false).pop()
|
|
139
|
+
const resultB = await client.queue('test-queue-v2-txn-ack-status-b').batch(1).wait(false).pop()
|
|
140
|
+
|
|
141
|
+
return {
|
|
142
|
+
success: resultA.length === 0 && resultB.length === 1,
|
|
143
|
+
message: 'Transaction with custom ack status completed'
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export async function transactionAtomicity(client) {
|
|
148
|
+
const queueA = await client.queue('test-queue-v2-txn-atomic-a').create()
|
|
149
|
+
const queueB = await client.queue('test-queue-v2-txn-atomic-b').create()
|
|
150
|
+
if (!queueA.configured || !queueB.configured) {
|
|
151
|
+
return { success: false, message: 'Queues not created' }
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Push a message to A
|
|
155
|
+
await client.queue('test-queue-v2-txn-atomic-a').push([{ data: { value: 100 } }])
|
|
156
|
+
|
|
157
|
+
// Pop from A
|
|
158
|
+
const messages = await client.queue('test-queue-v2-txn-atomic-a').batch(1).wait(false).pop()
|
|
159
|
+
if (messages.length === 0) {
|
|
160
|
+
return { success: false, message: 'No message to consume' }
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Successful transaction
|
|
164
|
+
await client
|
|
165
|
+
.transaction()
|
|
166
|
+
.ack(messages[0])
|
|
167
|
+
.queue('test-queue-v2-txn-atomic-b')
|
|
168
|
+
.push([{ data: { value: 200 } }])
|
|
169
|
+
.commit()
|
|
170
|
+
|
|
171
|
+
// Both operations should have succeeded atomically
|
|
172
|
+
const resultA = await client.queue('test-queue-v2-txn-atomic-a').batch(1).wait(false).pop()
|
|
173
|
+
const resultB = await client.queue('test-queue-v2-txn-atomic-b').batch(1).wait(false).pop()
|
|
174
|
+
|
|
175
|
+
return {
|
|
176
|
+
success: resultA.length === 0 && resultB.length === 1 && resultB[0].data.value === 200,
|
|
177
|
+
message: 'Transaction atomicity verified'
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export async function transactionChainedProcessing(client) {
|
|
182
|
+
const queue1 = await client.queue('test-queue-v2-txn-chain-1').create()
|
|
183
|
+
const queue2 = await client.queue('test-queue-v2-txn-chain-2').create()
|
|
184
|
+
const queue3 = await client.queue('test-queue-v2-txn-chain-3').create()
|
|
185
|
+
if (!queue1.configured || !queue2.configured || !queue3.configured) {
|
|
186
|
+
return { success: false, message: 'Queues not created' }
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Initial message
|
|
190
|
+
await client.queue('test-queue-v2-txn-chain-1').push([{ data: { step: 1, value: 10 } }])
|
|
191
|
+
|
|
192
|
+
// Transaction 1: Process from queue1 to queue2
|
|
193
|
+
const msg1 = await client.queue('test-queue-v2-txn-chain-1').batch(1).wait(false).pop()
|
|
194
|
+
if (msg1.length === 0) {
|
|
195
|
+
return { success: false, message: 'No message in queue 1' }
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
await client
|
|
199
|
+
.transaction()
|
|
200
|
+
.queue('test-queue-v2-txn-chain-2')
|
|
201
|
+
.push([{ data: { step: 2, value: msg1[0].data.value * 2 } }])
|
|
202
|
+
.ack(msg1[0])
|
|
203
|
+
.commit()
|
|
204
|
+
|
|
205
|
+
// Transaction 2: Process from queue2 to queue3
|
|
206
|
+
const msg2 = await client.queue('test-queue-v2-txn-chain-2').batch(1).wait(false).pop()
|
|
207
|
+
if (msg2.length === 0) {
|
|
208
|
+
return { success: false, message: 'No message in queue 2' }
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
await client
|
|
212
|
+
.transaction()
|
|
213
|
+
.queue('test-queue-v2-txn-chain-3')
|
|
214
|
+
.push([{ data: { step: 3, value: msg2[0].data.value + 5 } }])
|
|
215
|
+
.ack(msg2[0])
|
|
216
|
+
.commit()
|
|
217
|
+
|
|
218
|
+
// Verify final result
|
|
219
|
+
const result = await client.queue('test-queue-v2-txn-chain-3').batch(1).wait(false).pop()
|
|
220
|
+
const empty1 = await client.queue('test-queue-v2-txn-chain-1').batch(1).wait(false).pop()
|
|
221
|
+
const empty2 = await client.queue('test-queue-v2-txn-chain-2').batch(1).wait(false).pop()
|
|
222
|
+
|
|
223
|
+
return {
|
|
224
|
+
success: result.length === 1 && result[0].data.value === 25 && empty1.length === 0 && empty2.length === 0,
|
|
225
|
+
message: 'Chained transaction processing completed'
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
export async function transactionBatchPush(client) {
|
|
230
|
+
const queueA = await client.queue('test-queue-v2-txn-batch-a').create()
|
|
231
|
+
const queueB = await client.queue('test-queue-v2-txn-batch-b').create()
|
|
232
|
+
if (!queueA.configured || !queueB.configured) {
|
|
233
|
+
return { success: false, message: 'Queues not created' }
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// Push source message
|
|
237
|
+
await client.queue('test-queue-v2-txn-batch-a').push([{ data: { id: 'batch-source' } }])
|
|
238
|
+
|
|
239
|
+
// Pop from A
|
|
240
|
+
const messages = await client.queue('test-queue-v2-txn-batch-a').batch(1).wait(false).pop()
|
|
241
|
+
if (messages.length === 0) {
|
|
242
|
+
return { success: false, message: 'No message to consume' }
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// Transaction: Push multiple messages to B in a single batch, ack from A
|
|
246
|
+
await client
|
|
247
|
+
.transaction()
|
|
248
|
+
.queue('test-queue-v2-txn-batch-b')
|
|
249
|
+
.push([
|
|
250
|
+
{ data: { index: 1 } },
|
|
251
|
+
{ data: { index: 2 } },
|
|
252
|
+
{ data: { index: 3 } },
|
|
253
|
+
{ data: { index: 4 } },
|
|
254
|
+
{ data: { index: 5 } }
|
|
255
|
+
])
|
|
256
|
+
.ack(messages[0])
|
|
257
|
+
.commit()
|
|
258
|
+
|
|
259
|
+
// Verify all 5 messages in B
|
|
260
|
+
const resultB = await client.queue('test-queue-v2-txn-batch-b').batch(10).wait(false).pop()
|
|
261
|
+
const resultA = await client.queue('test-queue-v2-txn-batch-a').batch(1).wait(false).pop()
|
|
262
|
+
|
|
263
|
+
return {
|
|
264
|
+
success: resultB.length === 5 && resultA.length === 0,
|
|
265
|
+
message: 'Batch push in transaction completed'
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
export async function transactionWithPartitions(client) {
|
|
270
|
+
const queue = await client.queue('test-queue-v2-txn-partitions').create()
|
|
271
|
+
if (!queue.configured) {
|
|
272
|
+
return { success: false, message: 'Queue not created' }
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// Push messages to different partitions
|
|
276
|
+
await client.queue('test-queue-v2-txn-partitions').partition('p1').push([{ data: { partition: 'p1', value: 1 } }])
|
|
277
|
+
await client.queue('test-queue-v2-txn-partitions').partition('p2').push([{ data: { partition: 'p2', value: 2 } }])
|
|
278
|
+
|
|
279
|
+
// Pop from both partitions
|
|
280
|
+
const msg1 = await client.queue('test-queue-v2-txn-partitions').partition('p1').batch(1).wait(false).pop()
|
|
281
|
+
const msg2 = await client.queue('test-queue-v2-txn-partitions').partition('p2').batch(1).wait(false).pop()
|
|
282
|
+
|
|
283
|
+
if (msg1.length === 0 || msg2.length === 0) {
|
|
284
|
+
return { success: false, message: 'Messages not found in partitions' }
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// Transaction: Ack both messages from different partitions
|
|
288
|
+
await client
|
|
289
|
+
.transaction()
|
|
290
|
+
.ack(msg1[0])
|
|
291
|
+
.ack(msg2[0])
|
|
292
|
+
.commit()
|
|
293
|
+
|
|
294
|
+
// Verify both partitions are empty
|
|
295
|
+
const result1 = await client.queue('test-queue-v2-txn-partitions').partition('p1').batch(1).wait(false).pop()
|
|
296
|
+
const result2 = await client.queue('test-queue-v2-txn-partitions').partition('p2').batch(1).wait(false).pop()
|
|
297
|
+
|
|
298
|
+
return {
|
|
299
|
+
success: result1.length === 0 && result2.length === 0,
|
|
300
|
+
message: 'Transaction with multiple partitions completed'
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
export async function transactionWithConsumer(client) {
|
|
305
|
+
const queueA = await client.queue('test-queue-v2-txn-consumer-a').create()
|
|
306
|
+
const queueB = await client.queue('test-queue-v2-txn-consumer-b').create()
|
|
307
|
+
if (!queueA.configured || !queueB.configured) {
|
|
308
|
+
return { success: false, message: 'Queues not created' }
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// Push messages
|
|
312
|
+
await client.queue('test-queue-v2-txn-consumer-a').push([
|
|
313
|
+
{ data: { value: 1 } },
|
|
314
|
+
{ data: { value: 2 } },
|
|
315
|
+
{ data: { value: 3 } }
|
|
316
|
+
])
|
|
317
|
+
|
|
318
|
+
let processedCount = 0
|
|
319
|
+
|
|
320
|
+
// Consume with transaction
|
|
321
|
+
await client
|
|
322
|
+
.queue('test-queue-v2-txn-consumer-a')
|
|
323
|
+
.batch(1)
|
|
324
|
+
.wait(false)
|
|
325
|
+
.limit(3)
|
|
326
|
+
.each()
|
|
327
|
+
.autoAck(false) // Manual ack in transaction
|
|
328
|
+
.consume(async (msg) => {
|
|
329
|
+
await client
|
|
330
|
+
.transaction()
|
|
331
|
+
.queue('test-queue-v2-txn-consumer-b')
|
|
332
|
+
.push([{ data: { value: msg.data.value * 10 } }])
|
|
333
|
+
.ack(msg)
|
|
334
|
+
.commit()
|
|
335
|
+
|
|
336
|
+
processedCount++
|
|
337
|
+
})
|
|
338
|
+
|
|
339
|
+
// Verify results
|
|
340
|
+
const resultA = await client.queue('test-queue-v2-txn-consumer-a').batch(10).wait(false).pop()
|
|
341
|
+
const resultB = await client.queue('test-queue-v2-txn-consumer-b').batch(10).wait(false).pop()
|
|
342
|
+
|
|
343
|
+
return {
|
|
344
|
+
success: processedCount === 3 && resultA.length === 0 && resultB.length === 3,
|
|
345
|
+
message: 'Transaction with consumer completed'
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
export async function transactionEmptyCommit(client) {
|
|
350
|
+
const queue = await client.queue('test-queue-v2-txn-empty').create()
|
|
351
|
+
if (!queue.configured) {
|
|
352
|
+
return { success: false, message: 'Queue not created' }
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// Empty transaction - should throw error
|
|
356
|
+
let errorThrown = false
|
|
357
|
+
try {
|
|
358
|
+
await client.transaction().commit()
|
|
359
|
+
} catch (error) {
|
|
360
|
+
errorThrown = error.message === 'Transaction has no operations to commit'
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
return {
|
|
364
|
+
success: errorThrown,
|
|
365
|
+
message: 'Empty transaction correctly throws error'
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
export async function transactionLargePayload(client) {
|
|
370
|
+
const queueA = await client.queue('test-queue-v2-txn-large-a').create()
|
|
371
|
+
const queueB = await client.queue('test-queue-v2-txn-large-b').create()
|
|
372
|
+
if (!queueA.configured || !queueB.configured) {
|
|
373
|
+
return { success: false, message: 'Queues not created' }
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// Push a large message
|
|
377
|
+
const largeData = {
|
|
378
|
+
items: Array.from({ length: 1000 }, (_, i) => ({ id: i, data: `item-${i}` }))
|
|
379
|
+
}
|
|
380
|
+
await client.queue('test-queue-v2-txn-large-a').push([{ data: largeData }])
|
|
381
|
+
|
|
382
|
+
// Pop and process in transaction
|
|
383
|
+
const messages = await client.queue('test-queue-v2-txn-large-a').batch(1).wait(false).pop()
|
|
384
|
+
if (messages.length === 0) {
|
|
385
|
+
return { success: false, message: 'No message to consume' }
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
await client
|
|
389
|
+
.transaction()
|
|
390
|
+
.queue('test-queue-v2-txn-large-b')
|
|
391
|
+
.push([{ data: { count: messages[0].data.items.length } }])
|
|
392
|
+
.ack(messages[0])
|
|
393
|
+
.commit()
|
|
394
|
+
|
|
395
|
+
// Verify
|
|
396
|
+
const resultB = await client.queue('test-queue-v2-txn-large-b').batch(1).wait(false).pop()
|
|
397
|
+
|
|
398
|
+
return {
|
|
399
|
+
success: resultB.length === 1 && resultB[0].data.count === 1000,
|
|
400
|
+
message: 'Large payload transaction completed'
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
export async function transactionMultipleQueues(client) {
|
|
405
|
+
const queueA = await client.queue('test-queue-v2-txn-multi-q-a').create()
|
|
406
|
+
const queueB = await client.queue('test-queue-v2-txn-multi-q-b').create()
|
|
407
|
+
const queueC = await client.queue('test-queue-v2-txn-multi-q-c').create()
|
|
408
|
+
if (!queueA.configured || !queueB.configured || !queueC.configured) {
|
|
409
|
+
return { success: false, message: 'Queues not created' }
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
// Push messages to A and B
|
|
413
|
+
await client.queue('test-queue-v2-txn-multi-q-a').push([{ data: { source: 'A' } }])
|
|
414
|
+
await client.queue('test-queue-v2-txn-multi-q-b').push([{ data: { source: 'B' } }])
|
|
415
|
+
|
|
416
|
+
// Pop from both
|
|
417
|
+
const msgA = await client.queue('test-queue-v2-txn-multi-q-a').batch(1).wait(false).pop()
|
|
418
|
+
const msgB = await client.queue('test-queue-v2-txn-multi-q-b').batch(1).wait(false).pop()
|
|
419
|
+
|
|
420
|
+
if (msgA.length === 0 || msgB.length === 0) {
|
|
421
|
+
return { success: false, message: 'Messages not found' }
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
// Transaction: Ack from A and B, push to C
|
|
425
|
+
await client
|
|
426
|
+
.transaction()
|
|
427
|
+
.ack(msgA[0])
|
|
428
|
+
.ack(msgB[0])
|
|
429
|
+
.queue('test-queue-v2-txn-multi-q-c')
|
|
430
|
+
.push([{ data: { merged: true } }])
|
|
431
|
+
.commit()
|
|
432
|
+
|
|
433
|
+
// Verify all operations succeeded
|
|
434
|
+
const resultA = await client.queue('test-queue-v2-txn-multi-q-a').batch(1).wait(false).pop()
|
|
435
|
+
const resultB = await client.queue('test-queue-v2-txn-multi-q-b').batch(1).wait(false).pop()
|
|
436
|
+
const resultC = await client.queue('test-queue-v2-txn-multi-q-c').batch(1).wait(false).pop()
|
|
437
|
+
|
|
438
|
+
return {
|
|
439
|
+
success: resultA.length === 0 && resultB.length === 0 && resultC.length === 1,
|
|
440
|
+
message: 'Transaction across multiple queues completed'
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
|