@remit/sqs-client 0.0.13 → 0.0.15
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 +5 -1
- package/src/attempt-budget.test.ts +58 -0
- package/src/attempt-budget.ts +24 -0
- package/src/poller.ts +7 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remit/sqs-client",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.15",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"types": "src/index.ts",
|
|
@@ -9,6 +9,10 @@
|
|
|
9
9
|
"types": "./src/index.ts",
|
|
10
10
|
"default": "./src/index.ts"
|
|
11
11
|
},
|
|
12
|
+
"./attempt-budget": {
|
|
13
|
+
"types": "./src/attempt-budget.ts",
|
|
14
|
+
"default": "./src/attempt-budget.ts"
|
|
15
|
+
},
|
|
12
16
|
"./heartbeat": {
|
|
13
17
|
"types": "./src/heartbeat.ts",
|
|
14
18
|
"default": "./src/heartbeat.ts"
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { afterEach, describe, it } from "node:test";
|
|
3
|
+
import { attemptBudget } from "./attempt-budget.js";
|
|
4
|
+
|
|
5
|
+
describe("attemptBudget", () => {
|
|
6
|
+
afterEach(() => {
|
|
7
|
+
delete process.env.EXAMPLE_MAX_ATTEMPTS;
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
it("parses the named env var as a base-10 integer", () => {
|
|
11
|
+
assert.equal(
|
|
12
|
+
attemptBudget("EXAMPLE_MAX_ATTEMPTS", 3, {
|
|
13
|
+
EXAMPLE_MAX_ATTEMPTS: "5",
|
|
14
|
+
}),
|
|
15
|
+
5,
|
|
16
|
+
);
|
|
17
|
+
assert.equal(
|
|
18
|
+
attemptBudget("EXAMPLE_MAX_ATTEMPTS", 3, {
|
|
19
|
+
EXAMPLE_MAX_ATTEMPTS: "10",
|
|
20
|
+
}),
|
|
21
|
+
10,
|
|
22
|
+
);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it("reads only the named var, so budgets stay independent", () => {
|
|
26
|
+
assert.equal(
|
|
27
|
+
attemptBudget("EXAMPLE_MAX_ATTEMPTS", 3, {
|
|
28
|
+
OTHER_MAX_ATTEMPTS: "9",
|
|
29
|
+
}),
|
|
30
|
+
3,
|
|
31
|
+
);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it("falls back when the var is absent or empty", () => {
|
|
35
|
+
assert.equal(attemptBudget("EXAMPLE_MAX_ATTEMPTS", 3, {}), 3);
|
|
36
|
+
assert.equal(
|
|
37
|
+
attemptBudget("EXAMPLE_MAX_ATTEMPTS", 7, { EXAMPLE_MAX_ATTEMPTS: "" }),
|
|
38
|
+
7,
|
|
39
|
+
);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("falls back on a value that is not a positive integer", () => {
|
|
43
|
+
for (const raw of ["nope", "0", "-1", "NaN", " "]) {
|
|
44
|
+
assert.equal(
|
|
45
|
+
attemptBudget("EXAMPLE_MAX_ATTEMPTS", 3, {
|
|
46
|
+
EXAMPLE_MAX_ATTEMPTS: raw,
|
|
47
|
+
}),
|
|
48
|
+
3,
|
|
49
|
+
`expected ${JSON.stringify(raw)} to fall back`,
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it("reads process.env when no environment is supplied", () => {
|
|
55
|
+
process.env.EXAMPLE_MAX_ATTEMPTS = "4";
|
|
56
|
+
assert.equal(attemptBudget("EXAMPLE_MAX_ATTEMPTS", 3), 4);
|
|
57
|
+
});
|
|
58
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reads a handler's redelivery budget from the environment. CDK derives every
|
|
3
|
+
* `*_MAX_ATTEMPTS` var from the corresponding queue's own `MAX_RECEIVE_COUNT`
|
|
4
|
+
* (`infra/stacks/dev/stacks/remit-queue-stack.ts`, `deploy/vps/queues.json`)
|
|
5
|
+
* so a worker's idea of "last attempt" cannot drift from the redrive policy
|
|
6
|
+
* that actually dead-letters the record (issue #1270). SQS's
|
|
7
|
+
* `ApproximateReceiveCount` is the source of truth for how many times a record
|
|
8
|
+
* has been delivered; once it reaches this budget the current invocation is
|
|
9
|
+
* the last attempt, and the handler resolves exhaustion itself instead of
|
|
10
|
+
* letting the record dead-letter undiagnosed. The fallback keeps an
|
|
11
|
+
* environment that never injects the var — local dev, unit tests — behaving
|
|
12
|
+
* like production.
|
|
13
|
+
*/
|
|
14
|
+
export const attemptBudget = (
|
|
15
|
+
envName: string,
|
|
16
|
+
fallback: number,
|
|
17
|
+
processEnv: NodeJS.ProcessEnv = process.env,
|
|
18
|
+
): number => {
|
|
19
|
+
const raw = processEnv[envName];
|
|
20
|
+
if (!raw) return fallback;
|
|
21
|
+
const parsed = Number.parseInt(raw, 10);
|
|
22
|
+
if (!Number.isFinite(parsed) || parsed <= 0) return fallback;
|
|
23
|
+
return parsed;
|
|
24
|
+
};
|
package/src/poller.ts
CHANGED
|
@@ -61,7 +61,13 @@ export interface RunQueuePollerOptions {
|
|
|
61
61
|
// the extra receive per message is a millisecond against the local queue
|
|
62
62
|
// sidecar — the same total work either way.
|
|
63
63
|
const DEFAULT_MAX_MESSAGES = 1;
|
|
64
|
-
|
|
64
|
+
/**
|
|
65
|
+
* What a handler has before the queue redelivers the record underneath it.
|
|
66
|
+
* Exported because a handler that budgets its own wait has to agree with it;
|
|
67
|
+
* `deploy/vps/queues.json` sets the same number on the queue itself, and this
|
|
68
|
+
* is the one that applies wherever a target passes no override.
|
|
69
|
+
*/
|
|
70
|
+
export const DEFAULT_VISIBILITY_TIMEOUT_SECONDS = 300;
|
|
65
71
|
|
|
66
72
|
const pollTarget = async (
|
|
67
73
|
target: QueuePollerTarget,
|