@remit/sqs-client 0.0.14 → 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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remit/sqs-client",
3
- "version": "0.0.14",
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
+ };