@intelligems/sst 2.49.6-ig.8 → 2.49.8-ig.1
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/cli/commands/dev.js +10 -6
- package/constructs/AstroSite.d.ts +1 -1
- package/constructs/EdgeFunction.d.ts +1 -1
- package/constructs/EdgeFunction.js +8 -6
- package/constructs/Function.d.ts +3 -2
- package/constructs/Function.js +2 -1
- package/constructs/Job.d.ts +2 -2
- package/constructs/Job.js +4 -2
- package/constructs/NextjsSite.d.ts +1 -1
- package/constructs/NextjsSite.js +2 -2
- package/constructs/RemixSite.d.ts +1 -1
- package/constructs/SolidStartSite.d.ts +1 -1
- package/constructs/SsrFunction.d.ts +2 -2
- package/constructs/SsrFunction.js +7 -5
- package/constructs/SsrSite.d.ts +2 -2
- package/constructs/SsrSite.js +1 -1
- package/constructs/Stack.d.ts +1 -1
- package/constructs/Stack.js +1 -1
- package/constructs/SvelteKitSite.d.ts +1 -1
- package/constructs/deprecated/NextjsSite.d.ts +3 -3
- package/constructs/deprecated/NextjsSite.js +4 -1
- package/constructs/deprecated/cross-region-helper.js +3 -3
- package/iot.js +55 -0
- package/package.json +3 -3
- package/runtime/handlers/node.js +24 -2
- package/runtime/handlers.d.ts +4 -0
- package/runtime/memory-logging.d.ts +26 -0
- package/runtime/memory-logging.js +112 -0
- package/runtime/mono-build-config.d.ts +6 -3
- package/runtime/mono-build-config.js +34 -10
- package/runtime/server.js +35 -44
- package/runtime/stdout-attribution.d.ts +18 -0
- package/runtime/stdout-attribution.js +43 -0
- package/runtime/worker-config.d.ts +19 -0
- package/runtime/worker-config.js +26 -0
- package/runtime/worker-pool-logging.d.ts +2 -2
- package/runtime/worker-pool-logging.js +5 -5
- package/runtime/worker-pool.d.ts +77 -0
- package/runtime/worker-pool.js +162 -0
- package/runtime/workers.d.ts +33 -11
- package/runtime/workers.js +405 -513
- package/support/nodejs-runtime/index.mjs +214 -100
- package/watcher.js +2 -0
- package/LICENSE +0 -21
- package/README.md +0 -43
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bookkeeping for pooled dev workers.
|
|
3
|
+
*
|
|
4
|
+
* A pool key groups workers that can serve the same invocations: one key per
|
|
5
|
+
* function normally, one shared key for every Node function in mono-build
|
|
6
|
+
* mode. Each worker may hold up to `maxConcurrency` invocations at once, and a
|
|
7
|
+
* key never holds more than `maxWorkers` live (non-stale) workers, so the
|
|
8
|
+
* memory a key can consume is bounded by `maxWorkers` isolates.
|
|
9
|
+
*
|
|
10
|
+
* This module decides *which* worker serves a request and when a worker is
|
|
11
|
+
* retired. It never starts or stops threads itself: `onTerminate` is the hook
|
|
12
|
+
* the owner uses to actually stop the worker.
|
|
13
|
+
*/
|
|
14
|
+
export class WorkerPool {
|
|
15
|
+
opts;
|
|
16
|
+
pools = new Map();
|
|
17
|
+
byID = new Map();
|
|
18
|
+
constructor(opts) {
|
|
19
|
+
this.opts = opts;
|
|
20
|
+
}
|
|
21
|
+
add(worker) {
|
|
22
|
+
let pool = this.pools.get(worker.poolKey);
|
|
23
|
+
if (!pool) {
|
|
24
|
+
pool = [];
|
|
25
|
+
this.pools.set(worker.poolKey, pool);
|
|
26
|
+
}
|
|
27
|
+
pool.push(worker);
|
|
28
|
+
this.byID.set(worker.id, worker);
|
|
29
|
+
}
|
|
30
|
+
get(id) {
|
|
31
|
+
return this.byID.get(id);
|
|
32
|
+
}
|
|
33
|
+
workersFor(poolKey) {
|
|
34
|
+
return this.pools.get(poolKey) ?? [];
|
|
35
|
+
}
|
|
36
|
+
all() {
|
|
37
|
+
return [...this.byID.values()];
|
|
38
|
+
}
|
|
39
|
+
/** Live workers count toward the cap; stale ones are on their way out. */
|
|
40
|
+
liveCount(poolKey) {
|
|
41
|
+
return this.workersFor(poolKey).filter((w) => !w.stale).length;
|
|
42
|
+
}
|
|
43
|
+
canCreate(poolKey) {
|
|
44
|
+
return this.liveCount(poolKey) < this.opts.maxWorkers;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Least-loaded live worker with spare capacity, or undefined. Workers whose
|
|
48
|
+
* bundle is older than `currentMtime` are retired on the way: idle ones now,
|
|
49
|
+
* busy ones once they drain.
|
|
50
|
+
*/
|
|
51
|
+
pick(poolKey, currentMtime) {
|
|
52
|
+
const pool = this.pools.get(poolKey);
|
|
53
|
+
if (!pool || pool.length === 0)
|
|
54
|
+
return undefined;
|
|
55
|
+
for (const worker of [...pool]) {
|
|
56
|
+
if (currentMtime &&
|
|
57
|
+
worker.bundleMtime &&
|
|
58
|
+
currentMtime > worker.bundleMtime &&
|
|
59
|
+
!worker.stale) {
|
|
60
|
+
this.retire(worker, "stale_mtime");
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
let best;
|
|
64
|
+
for (const worker of pool) {
|
|
65
|
+
if (worker.stale)
|
|
66
|
+
continue;
|
|
67
|
+
if (worker.inFlight >= worker.maxConcurrency)
|
|
68
|
+
continue;
|
|
69
|
+
if (!best || worker.inFlight < best.inFlight)
|
|
70
|
+
best = worker;
|
|
71
|
+
}
|
|
72
|
+
return best;
|
|
73
|
+
}
|
|
74
|
+
/** Hand an invocation to a worker. */
|
|
75
|
+
checkout(worker, functionID) {
|
|
76
|
+
if (worker.idleTimer) {
|
|
77
|
+
clearTimeout(worker.idleTimer);
|
|
78
|
+
worker.idleTimer = undefined;
|
|
79
|
+
}
|
|
80
|
+
worker.inFlight += 1;
|
|
81
|
+
worker.functionID = functionID;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* An invocation finished. Returns what became of the worker: it is gone
|
|
85
|
+
* (stale and drained), idle (timer armed), or still busy.
|
|
86
|
+
*/
|
|
87
|
+
checkin(worker) {
|
|
88
|
+
if (worker.inFlight > 0)
|
|
89
|
+
worker.inFlight -= 1;
|
|
90
|
+
if (worker.inFlight > 0)
|
|
91
|
+
return "busy";
|
|
92
|
+
if (worker.stale) {
|
|
93
|
+
this.remove(worker);
|
|
94
|
+
this.opts.onTerminate(worker, "stale");
|
|
95
|
+
return "terminated";
|
|
96
|
+
}
|
|
97
|
+
worker.idleTimer = setTimeout(() => {
|
|
98
|
+
worker.idleTimer = undefined;
|
|
99
|
+
if (worker.inFlight > 0)
|
|
100
|
+
return;
|
|
101
|
+
if (!this.byID.has(worker.id))
|
|
102
|
+
return;
|
|
103
|
+
this.remove(worker);
|
|
104
|
+
this.opts.onTerminate(worker, "idle_timeout");
|
|
105
|
+
}, this.opts.idleTimeoutMs);
|
|
106
|
+
return "idle";
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* The code behind `poolKey` changed. Idle workers go now; busy ones are
|
|
110
|
+
* marked stale and go when they drain. Returns the ids of workers that
|
|
111
|
+
* were only marked.
|
|
112
|
+
*/
|
|
113
|
+
invalidate(poolKey, reason) {
|
|
114
|
+
const marked = [];
|
|
115
|
+
for (const worker of [...this.workersFor(poolKey)]) {
|
|
116
|
+
if (worker.inFlight === 0) {
|
|
117
|
+
this.remove(worker);
|
|
118
|
+
this.opts.onTerminate(worker, reason);
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
worker.stale = true;
|
|
122
|
+
marked.push(worker.id);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return marked;
|
|
126
|
+
}
|
|
127
|
+
/** Forget a worker that exited on its own (crash, OOM, self-timeout). */
|
|
128
|
+
remove(worker) {
|
|
129
|
+
if (worker.idleTimer) {
|
|
130
|
+
clearTimeout(worker.idleTimer);
|
|
131
|
+
worker.idleTimer = undefined;
|
|
132
|
+
}
|
|
133
|
+
this.byID.delete(worker.id);
|
|
134
|
+
const pool = this.pools.get(worker.poolKey);
|
|
135
|
+
if (!pool)
|
|
136
|
+
return;
|
|
137
|
+
const idx = pool.indexOf(worker);
|
|
138
|
+
if (idx >= 0)
|
|
139
|
+
pool.splice(idx, 1);
|
|
140
|
+
if (pool.length === 0)
|
|
141
|
+
this.pools.delete(worker.poolKey);
|
|
142
|
+
}
|
|
143
|
+
stats() {
|
|
144
|
+
let idle = 0;
|
|
145
|
+
let inFlight = 0;
|
|
146
|
+
for (const worker of this.byID.values()) {
|
|
147
|
+
if (worker.inFlight === 0)
|
|
148
|
+
idle += 1;
|
|
149
|
+
inFlight += worker.inFlight;
|
|
150
|
+
}
|
|
151
|
+
return { workers: this.byID.size, idle, inFlight };
|
|
152
|
+
}
|
|
153
|
+
retire(worker, reason) {
|
|
154
|
+
if (worker.inFlight === 0) {
|
|
155
|
+
this.remove(worker);
|
|
156
|
+
this.opts.onTerminate(worker, reason);
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
worker.stale = true;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
package/runtime/workers.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { EventPayload } from "../bus.js";
|
|
1
2
|
declare module "../bus.js" {
|
|
2
3
|
interface Events {
|
|
3
4
|
"worker.started": {
|
|
@@ -11,6 +12,8 @@ declare module "../bus.js" {
|
|
|
11
12
|
"worker.exited": {
|
|
12
13
|
workerID: string;
|
|
13
14
|
functionID: string;
|
|
15
|
+
/** Set for pooled workers: the id the runtime server keys on. */
|
|
16
|
+
pooledWorkerID?: string;
|
|
14
17
|
};
|
|
15
18
|
"worker.stdout": {
|
|
16
19
|
workerID: string;
|
|
@@ -39,27 +42,45 @@ declare module "../bus.js" {
|
|
|
39
42
|
};
|
|
40
43
|
}
|
|
41
44
|
}
|
|
45
|
+
interface Worker {
|
|
46
|
+
workerID: string;
|
|
47
|
+
functionID: string;
|
|
48
|
+
}
|
|
42
49
|
export declare const useRuntimeWorkers: () => Promise<{
|
|
43
|
-
fromID(workerID: string):
|
|
44
|
-
workerID: string;
|
|
45
|
-
functionID: string;
|
|
46
|
-
};
|
|
50
|
+
fromID(workerID: string): Worker;
|
|
47
51
|
getCurrentRequestID(workerID: string): string | undefined;
|
|
52
|
+
/**
|
|
53
|
+
* Who a response belongs to. Pooled workers may hold several requests,
|
|
54
|
+
* so the request id decides; non-pooled workers are their own AWS worker.
|
|
55
|
+
*/
|
|
56
|
+
resolveRequest(workerID: string, requestID?: string): {
|
|
57
|
+
awsWorkerID: string;
|
|
58
|
+
functionID: string;
|
|
59
|
+
} | undefined;
|
|
48
60
|
stdout(workerID: string, message: string): void;
|
|
49
61
|
exited(workerID: string): void;
|
|
50
|
-
onResponse(pooledWorkerID: string): void;
|
|
51
|
-
getAwsWorkerID(pooledWorkerID: string): string | undefined;
|
|
62
|
+
onResponse(pooledWorkerID: string, requestID?: string): void;
|
|
52
63
|
isPooled(workerID: string): boolean;
|
|
53
|
-
|
|
64
|
+
stats: () => {
|
|
65
|
+
workers: number;
|
|
66
|
+
inFlight: number;
|
|
67
|
+
queued: number;
|
|
68
|
+
};
|
|
69
|
+
subscribe: <Type extends "worker.started" | "worker.stopped" | "worker.exited" | "worker.stdout" | "worker.reused">(type: Type, cb: (payload: EventPayload<Type>) => void) => {
|
|
54
70
|
type: keyof import("../bus.js").Events;
|
|
55
71
|
cb: (payload: any) => void;
|
|
56
72
|
};
|
|
57
73
|
/**
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
74
|
+
* Warm the pool by invoking a Node function with warm pings.
|
|
75
|
+
*
|
|
76
|
+
* Each ping is marked as a fan-out *child* (`__WARMER_INVOCATION__ > 1`)
|
|
77
|
+
* so the app's lambda-warmer preloads its handlers and returns instead of
|
|
78
|
+
* fanning out to `concurrency` more Lambdas, which is what turned the old
|
|
79
|
+
* 30 pings into ~900 worker creations. The count is capped at the pool
|
|
80
|
+
* size, and pings go through the normal pool path, so warmup can never
|
|
81
|
+
* hold more isolates than steady state.
|
|
61
82
|
*/
|
|
62
|
-
triggerWarmup(count
|
|
83
|
+
triggerWarmup(count: number): Promise<{
|
|
63
84
|
warmed: number;
|
|
64
85
|
elapsed?: undefined;
|
|
65
86
|
} | {
|
|
@@ -67,3 +88,4 @@ export declare const useRuntimeWorkers: () => Promise<{
|
|
|
67
88
|
elapsed: number;
|
|
68
89
|
}>;
|
|
69
90
|
}>;
|
|
91
|
+
export {};
|