@remit/sqs-client 0.0.10 → 0.0.11
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/package.json +1 -1
- package/src/poller.test.ts +62 -1
- package/src/poller.ts +21 -3
package/package.json
CHANGED
package/src/poller.test.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import assert from "node:assert/strict";
|
|
2
2
|
import { describe, it, mock } from "node:test";
|
|
3
3
|
import { SQSClient } from "@aws-sdk/client-sqs";
|
|
4
|
-
import type { SQSBatchResponse, SQSEvent } from "aws-lambda";
|
|
4
|
+
import type { Context, SQSBatchResponse, SQSEvent } from "aws-lambda";
|
|
5
5
|
import { runQueuePoller } from "./poller.js";
|
|
6
6
|
|
|
7
7
|
const QUEUE_URL = "http://localhost:9324/000000000000/remit-test";
|
|
@@ -231,6 +231,67 @@ describe("runQueuePoller", () => {
|
|
|
231
231
|
assert.match(String(failures[0]?.arguments[0]?.error), /ENOSPC/);
|
|
232
232
|
});
|
|
233
233
|
|
|
234
|
+
// The `requestId` every line of one invocation is grouped by
|
|
235
|
+
// (deploy/vps/README.md, "Logs") is minted here, and it has to reach both the
|
|
236
|
+
// handler and the poller's own bracketing lines — otherwise grouping on it
|
|
237
|
+
// stops right before the line saying what happened to the message.
|
|
238
|
+
it("gives each batch its own requestId, on the handler context and on its own lines", async () => {
|
|
239
|
+
let receiveCalls = 0;
|
|
240
|
+
const sendMock = mock.method(
|
|
241
|
+
SQSClient.prototype,
|
|
242
|
+
"send",
|
|
243
|
+
// biome-ignore lint/suspicious/noExplicitAny: minimal SDK command shape, not worth typing per-command here
|
|
244
|
+
async function (this: SQSClient, command: any) {
|
|
245
|
+
if (command.constructor.name === "ReceiveMessageCommand") {
|
|
246
|
+
receiveCalls++;
|
|
247
|
+
if (receiveCalls >= 2) process.emit("SIGWINCH", "SIGWINCH");
|
|
248
|
+
return { Messages: [buildMessage(`m${receiveCalls}`)] };
|
|
249
|
+
}
|
|
250
|
+
if (command.constructor.name === "DeleteMessageCommand") return {};
|
|
251
|
+
throw new Error(`unexpected command: ${command.constructor.name}`);
|
|
252
|
+
},
|
|
253
|
+
);
|
|
254
|
+
|
|
255
|
+
const handler = mock.fn(
|
|
256
|
+
async (
|
|
257
|
+
_event: SQSEvent,
|
|
258
|
+
_context: Context,
|
|
259
|
+
): Promise<SQSBatchResponse> => ({ batchItemFailures: [] }),
|
|
260
|
+
);
|
|
261
|
+
const log = buildLog();
|
|
262
|
+
|
|
263
|
+
try {
|
|
264
|
+
await runQueuePoller({
|
|
265
|
+
targets: [{ queueUrl: QUEUE_URL, handler, functionName: "test-fn" }],
|
|
266
|
+
log,
|
|
267
|
+
signals: ["SIGWINCH"],
|
|
268
|
+
createHeartbeat: () => async () => {},
|
|
269
|
+
});
|
|
270
|
+
} finally {
|
|
271
|
+
sendMock.mock.restore();
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
const requestIds = handler.mock.calls.map(
|
|
275
|
+
(call) => call.arguments[1].awsRequestId,
|
|
276
|
+
);
|
|
277
|
+
assert.equal(requestIds.length, 2);
|
|
278
|
+
for (const requestId of requestIds)
|
|
279
|
+
assert.match(requestId, /^[0-9a-f-]{36}$/);
|
|
280
|
+
assert.notEqual(requestIds[0], requestIds[1]);
|
|
281
|
+
|
|
282
|
+
const bracketing = ["poller: invoking handler", "poller: batch processed"];
|
|
283
|
+
for (const message of bracketing) {
|
|
284
|
+
const lines = log.info.mock.calls.filter(
|
|
285
|
+
(call) => call.arguments[1] === message,
|
|
286
|
+
);
|
|
287
|
+
assert.equal(lines.length, 2, `expected two ${message} lines`);
|
|
288
|
+
assert.deepEqual(
|
|
289
|
+
lines.map((call) => call.arguments[0].requestId),
|
|
290
|
+
requestIds,
|
|
291
|
+
);
|
|
292
|
+
}
|
|
293
|
+
});
|
|
294
|
+
|
|
234
295
|
it("throws when constructed with no targets", async () => {
|
|
235
296
|
await assert.rejects(
|
|
236
297
|
() => runQueuePoller({ targets: [], log: buildLog() }),
|
package/src/poller.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
1
2
|
import { inspect } from "node:util";
|
|
2
3
|
import {
|
|
3
4
|
DeleteMessageCommand,
|
|
@@ -75,8 +76,6 @@ const pollTarget = async (
|
|
|
75
76
|
const maxMessages = target.maxMessages ?? DEFAULT_MAX_MESSAGES;
|
|
76
77
|
const visibilityTimeout =
|
|
77
78
|
target.visibilityTimeoutSeconds ?? DEFAULT_VISIBILITY_TIMEOUT_SECONDS;
|
|
78
|
-
const lambdaContext = { functionName: target.functionName } as Context;
|
|
79
|
-
|
|
80
79
|
log.info({ queue: queueName, maxMessages }, "poller: started");
|
|
81
80
|
|
|
82
81
|
// Always long-poll (SQS max WaitTimeSeconds). An empty long poll is free
|
|
@@ -146,8 +145,26 @@ const pollTarget = async (
|
|
|
146
145
|
);
|
|
147
146
|
if (messages.length === 0) continue;
|
|
148
147
|
|
|
148
|
+
// One batch is one handler invocation, so the id is minted per batch: it is
|
|
149
|
+
// the `requestId` every line of that invocation is grouped by (see
|
|
150
|
+
// deploy/vps/README.md, "Logs"). A context built once per target would put
|
|
151
|
+
// the whole queue's lifetime under one id, which correlates nothing.
|
|
152
|
+
//
|
|
153
|
+
// Minted before the poller's own bracketing lines rather than next to the
|
|
154
|
+
// handler call: grouping on the id has to reach the line saying whether the
|
|
155
|
+
// message was deleted or left for redelivery, which is what someone looks
|
|
156
|
+
// for after a failure.
|
|
157
|
+
const lambdaContext = {
|
|
158
|
+
functionName: target.functionName,
|
|
159
|
+
awsRequestId: randomUUID(),
|
|
160
|
+
} as Context;
|
|
161
|
+
|
|
149
162
|
log.info(
|
|
150
|
-
{
|
|
163
|
+
{
|
|
164
|
+
queue: queueName,
|
|
165
|
+
count: messages.length,
|
|
166
|
+
requestId: lambdaContext.awsRequestId,
|
|
167
|
+
},
|
|
151
168
|
"poller: invoking handler",
|
|
152
169
|
);
|
|
153
170
|
|
|
@@ -198,6 +215,7 @@ const pollTarget = async (
|
|
|
198
215
|
queue: queueName,
|
|
199
216
|
deleted: succeeded.length,
|
|
200
217
|
leftForRedelivery: failedIds.size,
|
|
218
|
+
requestId: lambdaContext.awsRequestId,
|
|
201
219
|
},
|
|
202
220
|
"poller: batch processed",
|
|
203
221
|
);
|