effortless-aws 0.30.0 → 0.32.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.
@@ -0,0 +1,109 @@
1
+ import {
2
+ buildDeps,
3
+ buildParams
4
+ } from "../chunk-HGSMOO4A.js";
5
+
6
+ // src/runtime/wrap-worker.ts
7
+ import { SQS } from "@aws-sdk/client-sqs";
8
+ import { ECSClient, UpdateServiceCommand } from "@aws-sdk/client-ecs";
9
+ var wrapWorker = (handler) => {
10
+ return async () => {
11
+ const queueUrl = process.env.EFF_WORKER_QUEUE_URL;
12
+ if (!queueUrl) throw new Error("Missing EFF_WORKER_QUEUE_URL env var");
13
+ const cluster = process.env.EFF_CLUSTER;
14
+ const service = process.env.EFF_SERVICE;
15
+ const idleTimeoutSec = process.env.EFF_IDLE_TIMEOUT ? Number(process.env.EFF_IDLE_TIMEOUT) : 300;
16
+ const concurrency = Math.min(Math.max(handler.__spec.concurrency ?? 1, 1), 10);
17
+ const sqs = new SQS({});
18
+ const ecs = new ECSClient({});
19
+ const deps = buildDeps(handler.deps);
20
+ const config = await buildParams(handler.config);
21
+ let ctx = {};
22
+ if (handler.setup) {
23
+ const setupArgs = {};
24
+ if (deps) setupArgs.deps = deps;
25
+ if (config) setupArgs.config = config;
26
+ const result = await handler.setup(setupArgs);
27
+ if (result && typeof result === "object") ctx = result;
28
+ }
29
+ const onMessage = handler.onMessage;
30
+ if (!onMessage) throw new Error("Worker has no onMessage handler");
31
+ const onError = handler.onError;
32
+ let lastMessageAt = Date.now();
33
+ try {
34
+ while (true) {
35
+ const resp = await sqs.receiveMessage({
36
+ QueueUrl: queueUrl,
37
+ MaxNumberOfMessages: concurrency,
38
+ WaitTimeSeconds: 20,
39
+ MessageSystemAttributeNames: ["ApproximateReceiveCount"]
40
+ });
41
+ const messages = resp?.Messages;
42
+ if (!messages || messages.length === 0) {
43
+ if (Date.now() - lastMessageAt > idleTimeoutSec * 1e3) {
44
+ console.log("[effortless:worker] Idle timeout reached, shutting down...");
45
+ break;
46
+ }
47
+ continue;
48
+ }
49
+ lastMessageAt = Date.now();
50
+ const results = await Promise.allSettled(
51
+ messages.map(async (sqsMsg) => {
52
+ const parsed = JSON.parse(sqsMsg.Body ?? "null");
53
+ await onMessage(parsed, ctx);
54
+ return sqsMsg.ReceiptHandle;
55
+ })
56
+ );
57
+ for (let i = 0; i < results.length; i++) {
58
+ const result = results[i];
59
+ const sqsMsg = messages[i];
60
+ if (result.status === "fulfilled") {
61
+ await sqs.deleteMessage({
62
+ QueueUrl: queueUrl,
63
+ ReceiptHandle: result.value
64
+ });
65
+ } else {
66
+ const retryCount = Number(sqsMsg.Attributes?.ApproximateReceiveCount ?? "1");
67
+ const parsed = JSON.parse(sqsMsg.Body ?? "null");
68
+ let action = "retry";
69
+ if (onError) {
70
+ try {
71
+ action = await onError({ error: result.reason, msg: parsed, retryCount, ...ctx });
72
+ } catch (e) {
73
+ console.error("[effortless:worker] onError threw", e);
74
+ }
75
+ } else {
76
+ console.error("[effortless:worker]", result.reason);
77
+ }
78
+ if (action === "delete") {
79
+ await sqs.deleteMessage({
80
+ QueueUrl: queueUrl,
81
+ ReceiptHandle: sqsMsg.ReceiptHandle
82
+ });
83
+ }
84
+ }
85
+ }
86
+ }
87
+ } finally {
88
+ if (handler.onCleanup) {
89
+ try {
90
+ await handler.onCleanup(ctx);
91
+ } catch (e) {
92
+ console.error("[effortless:worker] onCleanup error", e);
93
+ }
94
+ }
95
+ if (cluster && service) {
96
+ try {
97
+ await ecs.send(new UpdateServiceCommand({ cluster, service, desiredCount: 0 }));
98
+ console.log("[effortless:worker] Scaled service to 0");
99
+ } catch (e) {
100
+ console.error("[effortless:worker] Failed to scale down", e);
101
+ }
102
+ }
103
+ process.exit(0);
104
+ }
105
+ };
106
+ };
107
+ export {
108
+ wrapWorker
109
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "effortless-aws",
3
- "version": "0.30.0",
3
+ "version": "0.32.0",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "description": "Code-first AWS Lambda framework. Export handlers, deploy with one command.",
@@ -36,6 +36,7 @@
36
36
  },
37
37
  "devDependencies": {
38
38
  "@aws-sdk/client-dynamodb": "^3.975.0",
39
+ "@aws-sdk/client-ecs": "^3.1014.0",
39
40
  "@aws-sdk/client-s3": "^3.989.0",
40
41
  "@aws-sdk/client-sesv2": "^3.994.0",
41
42
  "@aws-sdk/client-sqs": "3.989.0",