@vellumai/cli 0.10.12-dev.202607250047.75b9ec6 → 0.10.12-dev.202607250309.e24b258
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 +1 -1
- package/src/__tests__/wake.test.ts +38 -1
- package/src/commands/wake.ts +47 -5
package/package.json
CHANGED
|
@@ -179,7 +179,7 @@ mock.module("../lib/nginx-ingress.js", () => ({
|
|
|
179
179
|
startRemoteWebIngress: startRemoteWebIngressMock,
|
|
180
180
|
}));
|
|
181
181
|
|
|
182
|
-
const { wake } = await import("../commands/wake.js");
|
|
182
|
+
const { wake, WEB_INGRESS_FLAG_RETRY } = await import("../commands/wake.js");
|
|
183
183
|
|
|
184
184
|
let tempDir: string;
|
|
185
185
|
let originalArgv: string[];
|
|
@@ -408,8 +408,18 @@ describe("vellum wake — web ingress restore", () => {
|
|
|
408
408
|
ingress: { enabled: true, publicBaseUrl: "https://assistant.example.com" },
|
|
409
409
|
};
|
|
410
410
|
|
|
411
|
+
const originalRetry = { ...WEB_INGRESS_FLAG_RETRY };
|
|
412
|
+
|
|
411
413
|
beforeEach(() => {
|
|
412
414
|
process.argv = ["bun", "vellum", "wake", "local-assistant"];
|
|
415
|
+
// Shrink the startup-window retry so failure-path tests stay fast.
|
|
416
|
+
WEB_INGRESS_FLAG_RETRY.attempts = 3;
|
|
417
|
+
WEB_INGRESS_FLAG_RETRY.intervalMs = 5;
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
afterEach(() => {
|
|
421
|
+
WEB_INGRESS_FLAG_RETRY.attempts = originalRetry.attempts;
|
|
422
|
+
WEB_INGRESS_FLAG_RETRY.intervalMs = originalRetry.intervalMs;
|
|
413
423
|
});
|
|
414
424
|
|
|
415
425
|
test("restores the edge when ingress is enabled, the flag is on, and it is not already running", async () => {
|
|
@@ -515,8 +525,35 @@ describe("vellum wake — web ingress restore", () => {
|
|
|
515
525
|
|
|
516
526
|
await wake();
|
|
517
527
|
|
|
528
|
+
// The probe retries through the startup window before giving up.
|
|
529
|
+
expect(isAssistantFeatureFlagEnabledMock.mock.calls.length).toBe(3);
|
|
518
530
|
expect(startRemoteWebIngressMock).not.toHaveBeenCalled();
|
|
519
531
|
expect(warnSpy).toHaveBeenCalled();
|
|
520
532
|
expect(logSpy).toHaveBeenCalledWith("Wake complete.");
|
|
521
533
|
});
|
|
534
|
+
|
|
535
|
+
test("a flag probe that fails while the gateway is starting retries and then restores", async () => {
|
|
536
|
+
loadRawConfigMock.mockReturnValue(enabledConfig);
|
|
537
|
+
isAssistantFeatureFlagEnabledMock
|
|
538
|
+
.mockRejectedValueOnce(
|
|
539
|
+
new Error(
|
|
540
|
+
'Failed to fetch feature flags: HTTP 503 {"status":"starting"}',
|
|
541
|
+
),
|
|
542
|
+
)
|
|
543
|
+
.mockRejectedValueOnce(
|
|
544
|
+
new Error(
|
|
545
|
+
'Failed to fetch feature flags: HTTP 503 {"status":"starting"}',
|
|
546
|
+
),
|
|
547
|
+
)
|
|
548
|
+
.mockResolvedValueOnce(true);
|
|
549
|
+
|
|
550
|
+
await wake();
|
|
551
|
+
|
|
552
|
+
expect(isAssistantFeatureFlagEnabledMock.mock.calls.length).toBe(3);
|
|
553
|
+
expect(logSpy).toHaveBeenCalledWith(
|
|
554
|
+
" Waiting for the gateway before restoring the web ingress edge...",
|
|
555
|
+
);
|
|
556
|
+
expect(startRemoteWebIngressMock).toHaveBeenCalled();
|
|
557
|
+
expect(logSpy).toHaveBeenCalledWith("Wake complete.");
|
|
558
|
+
});
|
|
522
559
|
});
|
package/src/commands/wake.ts
CHANGED
|
@@ -425,6 +425,52 @@ export async function wake(): Promise<void> {
|
|
|
425
425
|
}
|
|
426
426
|
}
|
|
427
427
|
|
|
428
|
+
/**
|
|
429
|
+
* Retry policy for the flag probe that gates the web-ingress restore. The
|
|
430
|
+
* gateway has typically been up for milliseconds at this point and answers
|
|
431
|
+
* `503 {"status":"starting"}` (or refuses connections) until its startup
|
|
432
|
+
* completes, so a single probe races it. Mutable so tests can shrink the
|
|
433
|
+
* window.
|
|
434
|
+
*/
|
|
435
|
+
export const WEB_INGRESS_FLAG_RETRY = {
|
|
436
|
+
attempts: 15,
|
|
437
|
+
intervalMs: 2_000,
|
|
438
|
+
};
|
|
439
|
+
|
|
440
|
+
/**
|
|
441
|
+
* Probe the `web-remote-ingress` flag, riding out the gateway's startup
|
|
442
|
+
* window: transient failures retry on an interval until the attempt budget is
|
|
443
|
+
* spent, then the last error propagates to the caller's warn path.
|
|
444
|
+
*/
|
|
445
|
+
async function verifyWebIngressFlagWithRetry(
|
|
446
|
+
assistantId: string,
|
|
447
|
+
gatewayPort: number,
|
|
448
|
+
): Promise<boolean> {
|
|
449
|
+
let lastError: unknown;
|
|
450
|
+
for (let attempt = 1; attempt <= WEB_INGRESS_FLAG_RETRY.attempts; attempt++) {
|
|
451
|
+
try {
|
|
452
|
+
return await isAssistantFeatureFlagEnabled(
|
|
453
|
+
assistantId,
|
|
454
|
+
WEB_REMOTE_INGRESS_FLAG,
|
|
455
|
+
{ runtimeUrl: `http://127.0.0.1:${gatewayPort}` },
|
|
456
|
+
);
|
|
457
|
+
} catch (err) {
|
|
458
|
+
lastError = err;
|
|
459
|
+
if (attempt === 1) {
|
|
460
|
+
console.log(
|
|
461
|
+
" Waiting for the gateway before restoring the web ingress edge...",
|
|
462
|
+
);
|
|
463
|
+
}
|
|
464
|
+
if (attempt < WEB_INGRESS_FLAG_RETRY.attempts) {
|
|
465
|
+
await new Promise((resolve) =>
|
|
466
|
+
setTimeout(resolve, WEB_INGRESS_FLAG_RETRY.intervalMs),
|
|
467
|
+
);
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
throw lastError;
|
|
472
|
+
}
|
|
473
|
+
|
|
428
474
|
/**
|
|
429
475
|
* Bring the nginx web ingress edge back up after a wake when the workspace
|
|
430
476
|
* config still wants it. Only restores when ingress is explicitly enabled with
|
|
@@ -460,11 +506,7 @@ async function restoreWebIngressIfEnabled(
|
|
|
460
506
|
|
|
461
507
|
let flagEnabled: boolean;
|
|
462
508
|
try {
|
|
463
|
-
flagEnabled = await
|
|
464
|
-
assistantId,
|
|
465
|
-
WEB_REMOTE_INGRESS_FLAG,
|
|
466
|
-
{ runtimeUrl: `http://127.0.0.1:${gatewayPort}` },
|
|
467
|
-
);
|
|
509
|
+
flagEnabled = await verifyWebIngressFlagWithRetry(assistantId, gatewayPort);
|
|
468
510
|
} catch (err) {
|
|
469
511
|
console.warn(
|
|
470
512
|
` Could not verify the \`${WEB_REMOTE_INGRESS_FLAG}\` flag to restore the web ingress edge; leaving it down. Bring it up manually with \`vellum nginx-ingress up\`. ${
|