@evident-ai/runner-cdk 3.6.1-dev.8d3e144 → 3.6.1-dev.d5a3d9d
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.
|
@@ -49795,6 +49795,7 @@ var RUN_HOOK_PAYLOAD_MAX_BYTES = 16384;
|
|
|
49795
49795
|
var SUSPENDING_POLL_ATTEMPTS = 4;
|
|
49796
49796
|
var SUSPENDING_POLL_INTERVAL_MS = 500;
|
|
49797
49797
|
var MICROVM_MAX_RUN_SECONDS = 28800;
|
|
49798
|
+
var MICROVM_EXPIRY_REFRESH_WINDOW_MS = 2 * 60 * 6e4;
|
|
49798
49799
|
|
|
49799
49800
|
// src/microvm/controller/handle-doorbell.ts
|
|
49800
49801
|
var import_node_crypto12 = require("node:crypto");
|
|
@@ -49924,6 +49925,7 @@ var REASON = {
|
|
|
49924
49925
|
alreadyStarting: "already_starting",
|
|
49925
49926
|
terminated: "terminated_or_terminating",
|
|
49926
49927
|
imageVersionOutdated: "image_version_outdated",
|
|
49928
|
+
expiringSoon: "microvm_expiring_soon",
|
|
49927
49929
|
resumeFailedFallingBackToRun: "resume_failed_falling_back_to_run",
|
|
49928
49930
|
suspendingPollExhausted: "suspending_poll_exhausted",
|
|
49929
49931
|
suspendWithoutMicrovmId: "suspend_without_microvm_id",
|
|
@@ -50001,6 +50003,15 @@ function compareImageVersions(a7, b7) {
|
|
|
50001
50003
|
}
|
|
50002
50004
|
return 0;
|
|
50003
50005
|
}
|
|
50006
|
+
function isWithinExpiryRefreshWindow(doorbellRequest, startedAt, nowMs) {
|
|
50007
|
+
if (startedAt === void 0 || !Number.isFinite(startedAt.getTime())) {
|
|
50008
|
+
console.warn(
|
|
50009
|
+
`[doorbell] GetMicrovm reported no finite startedAt for runner ${doorbellRequest.runnerId}; resuming`
|
|
50010
|
+
);
|
|
50011
|
+
return false;
|
|
50012
|
+
}
|
|
50013
|
+
return startedAt.getTime() + MICROVM_MAX_RUN_SECONDS * 1e3 - nowMs < MICROVM_EXPIRY_REFRESH_WINDOW_MS;
|
|
50014
|
+
}
|
|
50004
50015
|
async function shouldRecreateForNewerImage(doorbellRequest, shape, runningVersion, microvm) {
|
|
50005
50016
|
if (runningVersion === void 0) {
|
|
50006
50017
|
console.warn(
|
|
@@ -50039,6 +50050,7 @@ async function handleDoorbell({
|
|
|
50039
50050
|
controllerSigningSecret,
|
|
50040
50051
|
shapes,
|
|
50041
50052
|
microvm,
|
|
50053
|
+
nowMs,
|
|
50042
50054
|
sleep: sleep4,
|
|
50043
50055
|
random
|
|
50044
50056
|
}) {
|
|
@@ -50078,11 +50090,11 @@ async function handleDoorbell({
|
|
|
50078
50090
|
microvmId: doorbellRequest.microvmId
|
|
50079
50091
|
});
|
|
50080
50092
|
}
|
|
50081
|
-
return handleWakeDoorbell(doorbellRequest, resolvedShape, microvm, timing);
|
|
50093
|
+
return handleWakeDoorbell(doorbellRequest, resolvedShape, microvm, timing, nowMs);
|
|
50082
50094
|
}
|
|
50083
50095
|
return suspendMicrovm(doorbellRequest, microvm, timing);
|
|
50084
50096
|
}
|
|
50085
|
-
async function handleWakeDoorbell(doorbellRequest, shape, microvm, timing) {
|
|
50097
|
+
async function handleWakeDoorbell(doorbellRequest, shape, microvm, timing, nowMs) {
|
|
50086
50098
|
if (doorbellRequest.microvmId === void 0) {
|
|
50087
50099
|
return runMicrovm(doorbellRequest, shape, microvm, timing, false, REASON.noMicrovmId);
|
|
50088
50100
|
}
|
|
@@ -50132,7 +50144,19 @@ async function handleWakeDoorbell(doorbellRequest, shape, microvm, timing) {
|
|
|
50132
50144
|
startedAt: described.startedAt,
|
|
50133
50145
|
imageVersion: described.imageVersion
|
|
50134
50146
|
});
|
|
50135
|
-
case "SUSPENDED":
|
|
50147
|
+
case "SUSPENDED": {
|
|
50148
|
+
const resumeStartedAt = described.startedAt === void 0 || Number.isFinite(described.startedAt.getTime()) ? described.startedAt : void 0;
|
|
50149
|
+
if (isWithinExpiryRefreshWindow(doorbellRequest, described.startedAt, nowMs)) {
|
|
50150
|
+
return runMicrovm(
|
|
50151
|
+
doorbellRequest,
|
|
50152
|
+
shape,
|
|
50153
|
+
microvm,
|
|
50154
|
+
timing,
|
|
50155
|
+
polled,
|
|
50156
|
+
REASON.expiringSoon,
|
|
50157
|
+
state3
|
|
50158
|
+
);
|
|
50159
|
+
}
|
|
50136
50160
|
if (doorbellRequest.recreateOnOutdatedImage === true && await shouldRecreateForNewerImage(doorbellRequest, shape, described.imageVersion, microvm)) {
|
|
50137
50161
|
return runMicrovm(
|
|
50138
50162
|
doorbellRequest,
|
|
@@ -50151,9 +50175,10 @@ async function handleWakeDoorbell(doorbellRequest, shape, microvm, timing) {
|
|
|
50151
50175
|
microvm,
|
|
50152
50176
|
timing,
|
|
50153
50177
|
polled,
|
|
50154
|
-
|
|
50178
|
+
resumeStartedAt,
|
|
50155
50179
|
described.imageVersion
|
|
50156
50180
|
);
|
|
50181
|
+
}
|
|
50157
50182
|
default:
|
|
50158
50183
|
return runMicrovm(
|
|
50159
50184
|
doorbellRequest,
|
|
@@ -50514,6 +50539,7 @@ var handler = async (event) => {
|
|
|
50514
50539
|
controllerSigningSecret,
|
|
50515
50540
|
shapes,
|
|
50516
50541
|
microvm: createRuntimeMicrovm(executionRoleArn),
|
|
50542
|
+
nowMs: Date.now(),
|
|
50517
50543
|
sleep: sleep3,
|
|
50518
50544
|
random: Math.random
|
|
50519
50545
|
});
|
|
@@ -5,5 +5,6 @@ export declare const RUN_HOOK_PAYLOAD_MAX_BYTES = 16384;
|
|
|
5
5
|
export declare const SUSPENDING_POLL_ATTEMPTS = 4;
|
|
6
6
|
export declare const SUSPENDING_POLL_INTERVAL_MS = 500;
|
|
7
7
|
export declare const MICROVM_MAX_RUN_SECONDS = 28800;
|
|
8
|
+
export declare const MICROVM_EXPIRY_REFRESH_WINDOW_MS: number;
|
|
8
9
|
export declare const SESSION_CLEANUP_MAX_AGE = "24h";
|
|
9
10
|
export declare const CONTROLLER_SIGNING_SECRET_KEY = "CONTROLLER_SIGNING_SECRET";
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// across them. The image template pins matching copies, guarded by
|
|
5
5
|
// `microvm/image/dockerfile.test.ts`.
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.CONTROLLER_SIGNING_SECRET_KEY = exports.SESSION_CLEANUP_MAX_AGE = exports.MICROVM_MAX_RUN_SECONDS = exports.SUSPENDING_POLL_INTERVAL_MS = exports.SUSPENDING_POLL_ATTEMPTS = exports.RUN_HOOK_PAYLOAD_MAX_BYTES = exports.HOOK_TIMEOUT_SECONDS = exports.HOOKS_DIR = exports.HOOKS_PORT = void 0;
|
|
7
|
+
exports.CONTROLLER_SIGNING_SECRET_KEY = exports.SESSION_CLEANUP_MAX_AGE = exports.MICROVM_EXPIRY_REFRESH_WINDOW_MS = exports.MICROVM_MAX_RUN_SECONDS = exports.SUSPENDING_POLL_INTERVAL_MS = exports.SUSPENDING_POLL_ATTEMPTS = exports.RUN_HOOK_PAYLOAD_MAX_BYTES = exports.HOOK_TIMEOUT_SECONDS = exports.HOOKS_DIR = exports.HOOKS_PORT = void 0;
|
|
8
8
|
// The port the image's hook server binds, baked into the published Dockerfile
|
|
9
9
|
// (`ENV HOOKS_PORT`) and passed to the construct as `hooksPort`. Exported from
|
|
10
10
|
// the package index because a consumer building the published image context
|
|
@@ -32,6 +32,9 @@ exports.SUSPENDING_POLL_INTERVAL_MS = 500;
|
|
|
32
32
|
// longer than any VM can possibly still be running, no VM started before the
|
|
33
33
|
// deactivation can outlive it. The two MUST move together.
|
|
34
34
|
exports.MICROVM_MAX_RUN_SECONDS = 28800;
|
|
35
|
+
// A SUSPENDED VM with less than this left against `MICROVM_MAX_RUN_SECONDS`
|
|
36
|
+
// is started fresh so AWS cannot terminate it during a task.
|
|
37
|
+
exports.MICROVM_EXPIRY_REFRESH_WINDOW_MS = 2 * 60 * 60_000;
|
|
35
38
|
// Auto-cleanup (issue #190): `evident run` reads this directly from the Fargate
|
|
36
39
|
// task and MicroVM image. Setting a retention rule makes it sweep OpenCode
|
|
37
40
|
// sessions idle longer than 24h; protected/active sessions are never touched.
|
|
@@ -17,11 +17,12 @@ export type DoorbellResult = {
|
|
|
17
17
|
kind: ActionKind;
|
|
18
18
|
};
|
|
19
19
|
};
|
|
20
|
-
export declare function handleDoorbell({ rawBody, signatureHeader, controllerSigningSecret, shapes, microvm, sleep, random, }: {
|
|
20
|
+
export declare function handleDoorbell({ rawBody, signatureHeader, controllerSigningSecret, shapes, microvm, nowMs, sleep, random, }: {
|
|
21
21
|
rawBody: string;
|
|
22
22
|
signatureHeader: string | undefined;
|
|
23
23
|
controllerSigningSecret: string;
|
|
24
24
|
shapes: ShapeCatalogue;
|
|
25
25
|
microvm: MicrovmClient;
|
|
26
|
+
nowMs: number;
|
|
26
27
|
} & Timing): Promise<DoorbellResult>;
|
|
27
28
|
export {};
|
|
@@ -14,6 +14,7 @@ const REASON = {
|
|
|
14
14
|
alreadyStarting: 'already_starting',
|
|
15
15
|
terminated: 'terminated_or_terminating',
|
|
16
16
|
imageVersionOutdated: 'image_version_outdated',
|
|
17
|
+
expiringSoon: 'microvm_expiring_soon',
|
|
17
18
|
resumeFailedFallingBackToRun: 'resume_failed_falling_back_to_run',
|
|
18
19
|
suspendingPollExhausted: 'suspending_poll_exhausted',
|
|
19
20
|
suspendWithoutMicrovmId: 'suspend_without_microvm_id',
|
|
@@ -128,6 +129,14 @@ function compareImageVersions(a, b) {
|
|
|
128
129
|
}
|
|
129
130
|
return 0;
|
|
130
131
|
}
|
|
132
|
+
function isWithinExpiryRefreshWindow(doorbellRequest, startedAt, nowMs) {
|
|
133
|
+
if (startedAt === undefined || !Number.isFinite(startedAt.getTime())) {
|
|
134
|
+
console.warn(`[doorbell] GetMicrovm reported no finite startedAt for runner ${doorbellRequest.runnerId}; ` +
|
|
135
|
+
'resuming');
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
return (startedAt.getTime() + constants_1.MICROVM_MAX_RUN_SECONDS * 1000 - nowMs < constants_1.MICROVM_EXPIRY_REFRESH_WINDOW_MS);
|
|
139
|
+
}
|
|
131
140
|
/**
|
|
132
141
|
* Whether an opted-in doorbell should throw away and recreate the SUSPENDED VM
|
|
133
142
|
* because a newer image has been published since it booted.
|
|
@@ -174,7 +183,7 @@ async function shouldRecreateForNewerImage(doorbellRequest, shape, runningVersio
|
|
|
174
183
|
// been deactivated, and recreating would not roll it forward. Resume.
|
|
175
184
|
return compareImageVersions(running, latest) < 0;
|
|
176
185
|
}
|
|
177
|
-
async function handleDoorbell({ rawBody, signatureHeader, controllerSigningSecret, shapes, microvm, sleep, random, }) {
|
|
186
|
+
async function handleDoorbell({ rawBody, signatureHeader, controllerSigningSecret, shapes, microvm, nowMs, sleep, random, }) {
|
|
178
187
|
if (!(0, sdk_1.verifyEvidentSignature)(rawBody, signatureHeader, controllerSigningSecret)) {
|
|
179
188
|
return decide({
|
|
180
189
|
statusCode: 401,
|
|
@@ -223,11 +232,11 @@ async function handleDoorbell({ rawBody, signatureHeader, controllerSigningSecre
|
|
|
223
232
|
microvmId: doorbellRequest.microvmId,
|
|
224
233
|
});
|
|
225
234
|
}
|
|
226
|
-
return handleWakeDoorbell(doorbellRequest, resolvedShape, microvm, timing);
|
|
235
|
+
return handleWakeDoorbell(doorbellRequest, resolvedShape, microvm, timing, nowMs);
|
|
227
236
|
}
|
|
228
237
|
return suspendMicrovm(doorbellRequest, microvm, timing);
|
|
229
238
|
}
|
|
230
|
-
async function handleWakeDoorbell(doorbellRequest, shape, microvm, timing) {
|
|
239
|
+
async function handleWakeDoorbell(doorbellRequest, shape, microvm, timing, nowMs) {
|
|
231
240
|
if (doorbellRequest.microvmId === undefined) {
|
|
232
241
|
return runMicrovm(doorbellRequest, shape, microvm, timing, false, REASON.noMicrovmId);
|
|
233
242
|
}
|
|
@@ -285,16 +294,23 @@ async function handleWakeDoorbell(doorbellRequest, shape, microvm, timing) {
|
|
|
285
294
|
startedAt: described.startedAt,
|
|
286
295
|
imageVersion: described.imageVersion,
|
|
287
296
|
});
|
|
288
|
-
case 'SUSPENDED':
|
|
297
|
+
case 'SUSPENDED': {
|
|
289
298
|
// False/absent disables silent automatic roll-forward; an explicit restart
|
|
290
299
|
// request (#1906) can still set the same wire flag. Recreate loses VM-local
|
|
291
300
|
// filesystem state; durable provider credentials survive in object storage,
|
|
292
301
|
// but a manual paste/upload not yet synced there may be lost (#2071).
|
|
302
|
+
const resumeStartedAt = described.startedAt === undefined || Number.isFinite(described.startedAt.getTime())
|
|
303
|
+
? described.startedAt
|
|
304
|
+
: undefined;
|
|
305
|
+
if (isWithinExpiryRefreshWindow(doorbellRequest, described.startedAt, nowMs)) {
|
|
306
|
+
return runMicrovm(doorbellRequest, shape, microvm, timing, polled, REASON.expiringSoon, state);
|
|
307
|
+
}
|
|
293
308
|
if (doorbellRequest.recreateOnOutdatedImage === true &&
|
|
294
309
|
(await shouldRecreateForNewerImage(doorbellRequest, shape, described.imageVersion, microvm))) {
|
|
295
310
|
return runMicrovm(doorbellRequest, shape, microvm, timing, polled, REASON.imageVersionOutdated, state);
|
|
296
311
|
}
|
|
297
|
-
return resumeMicrovm(doorbellRequest, doorbellRequest.microvmId, shape, microvm, timing, polled,
|
|
312
|
+
return resumeMicrovm(doorbellRequest, doorbellRequest.microvmId, shape, microvm, timing, polled, resumeStartedAt, described.imageVersion);
|
|
313
|
+
}
|
|
298
314
|
default:
|
|
299
315
|
// TERMINATED, TERMINATING, not_found — gone or going, so a fresh VM either
|
|
300
316
|
// way. This is what self-heals a stale `microvm_id`.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@evident-ai/runner-cdk",
|
|
3
|
-
"version": "3.6.1-dev.
|
|
3
|
+
"version": "3.6.1-dev.d5a3d9d",
|
|
4
4
|
"description": "Reusable CDK constructs for an Evident agent runner: a single scale-to-zero Fargate runner (task + service + per-agent self-stop role + waker Lambda), or a per-session AWS Lambda MicroVM that boots on demand and suspends between messages. Instantiate once per agent from your own stack.",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"//build-bundled-deps": "Builds the workspace dependencies whose dist/ output the direct runner-cdk build chain consumes: lambda-microvm-cdk for the public construct types, lambda-microvm-runtime for runner-microvm-image's hook-server bundle, and runner-microvm-image for that bundle itself. Chained into `build` rather than left to turbo's `^build` because callers outside turbo invoke `pnpm --filter @evident-ai/runner-cdk build` directly, which bypasses turbo entirely.",
|
|
19
19
|
"build-bundled-deps": "pnpm --filter @evident-ai/lambda-microvm-cdk build && pnpm --filter @evident-ai/lambda-microvm-runtime build && pnpm --filter runner-microvm-image build",
|
|
20
20
|
"typecheck": "tsc --noEmit",
|
|
21
|
-
"test": "node --test --require
|
|
21
|
+
"test": "node --test --require tsx/cjs 'src/**/*.test.ts'",
|
|
22
22
|
"format": "prettier --write 'src/**/*.ts'",
|
|
23
23
|
"lint": "eslint 'src/**/*.ts' --max-warnings=0"
|
|
24
24
|
},
|