veryfront 0.1.1054 → 0.1.1055
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/esm/cli/commands/serve/command.d.ts.map +1 -1
- package/esm/cli/commands/serve/command.js +8 -6
- package/esm/deno.js +1 -1
- package/esm/src/server/graceful-shutdown.d.ts +59 -0
- package/esm/src/server/graceful-shutdown.d.ts.map +1 -0
- package/esm/src/server/graceful-shutdown.js +118 -0
- package/esm/src/server/index.d.ts +1 -0
- package/esm/src/server/index.d.ts.map +1 -1
- package/esm/src/server/index.js +1 -0
- package/esm/src/server/production-server.d.ts.map +1 -1
- package/esm/src/server/production-server.js +9 -36
- package/esm/src/utils/version-constant.d.ts +1 -1
- package/esm/src/utils/version-constant.js +1 -1
- package/package.json +5 -5
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/serve/command.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/serve/command.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,UAAU,GAAG,OAAO,GAAG,YAAY,CAAC;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,OAAO,CAAC;CAChB;AA+FD,wBAAsB,YAAY,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAcvE"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { cwd } from "../../../src/platform/index.js";
|
|
2
|
+
import { gracefullyShutdownProductionServer } from "../../../src/server/index.js";
|
|
2
3
|
import { cliLogger } from "../../utils/index.js";
|
|
3
4
|
import { exitProcess, registerTerminationSignals, showLogo } from "../../utils/index.js";
|
|
4
5
|
import { generateDefaultProjectId } from "../../utils/project.js";
|
|
@@ -56,10 +57,13 @@ async function runProductionServer(options) {
|
|
|
56
57
|
if (shuttingDown)
|
|
57
58
|
return;
|
|
58
59
|
shuttingDown = true;
|
|
59
|
-
cliLogger.info(`Received ${signal}, shutting down production server...`);
|
|
60
60
|
try {
|
|
61
|
-
|
|
62
|
-
|
|
61
|
+
await gracefullyShutdownProductionServer({
|
|
62
|
+
signal,
|
|
63
|
+
abort: () => shutdownController.abort(),
|
|
64
|
+
stop: server.stop,
|
|
65
|
+
logger: cliLogger,
|
|
66
|
+
});
|
|
63
67
|
}
|
|
64
68
|
catch (error) {
|
|
65
69
|
cliLogger.warn("Error while shutting down production server:", error);
|
|
@@ -68,9 +72,7 @@ async function runProductionServer(options) {
|
|
|
68
72
|
exitProcess(0);
|
|
69
73
|
}
|
|
70
74
|
};
|
|
71
|
-
registerTerminationSignals(
|
|
72
|
-
void shutdown(signal);
|
|
73
|
-
});
|
|
75
|
+
registerTerminationSignals(shutdown);
|
|
74
76
|
await new Promise(() => { });
|
|
75
77
|
}
|
|
76
78
|
export async function serveCommand(options) {
|
package/esm/deno.js
CHANGED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/** Default drain timeout leaves headroom under Kubernetes' default 30 second grace period. */
|
|
2
|
+
export declare const DEFAULT_SHUTDOWN_DRAIN_TIMEOUT_MS = 25000;
|
|
3
|
+
/** Cleanup timeout keeps total shutdown below the default 30 second grace period. */
|
|
4
|
+
export declare const DEFAULT_SHUTDOWN_CLEANUP_TIMEOUT_MS = 4000;
|
|
5
|
+
interface GracefulShutdownRequestTracker {
|
|
6
|
+
getInFlightCount(): number;
|
|
7
|
+
waitForDrain(timeoutMs: number): Promise<boolean>;
|
|
8
|
+
shutdown(): void;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Inputs required to drain and stop a production server process.
|
|
12
|
+
*
|
|
13
|
+
* This lifecycle mutates process-wide readiness, shutdown, and request-tracking
|
|
14
|
+
* state. Use it once from the process signal handler, not for individual server
|
|
15
|
+
* instances or requests.
|
|
16
|
+
*/
|
|
17
|
+
export interface GracefulProductionShutdownOptions {
|
|
18
|
+
/** Operating-system signal that initiated shutdown. */
|
|
19
|
+
signal: "SIGINT" | "SIGTERM";
|
|
20
|
+
/** Maximum drain time. Defaults to SHUTDOWN_DRAIN_TIMEOUT_MS or 25 seconds. */
|
|
21
|
+
drainTimeoutMs?: number;
|
|
22
|
+
/** Total time allowed for cleanup after draining. Defaults to 4 seconds. */
|
|
23
|
+
cleanupTimeoutMs?: number;
|
|
24
|
+
/** Stops signal-aware background work before the HTTP server closes. */
|
|
25
|
+
abort: () => void;
|
|
26
|
+
/** Stops the production HTTP server. */
|
|
27
|
+
stop: () => Promise<void>;
|
|
28
|
+
/** Releases optional bootstrap resources before the server closes. */
|
|
29
|
+
dispose?: () => void | Promise<void>;
|
|
30
|
+
/** Logger used for shutdown progress and failures. */
|
|
31
|
+
logger: {
|
|
32
|
+
info(message: string, context?: Record<string, unknown>): void;
|
|
33
|
+
warn(message: string, context?: unknown): void;
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
interface GracefulProductionShutdownDependencies {
|
|
37
|
+
markServerShuttingDown: () => void;
|
|
38
|
+
setServerInitialized: (ready: boolean) => void;
|
|
39
|
+
requestTracker: GracefulShutdownRequestTracker;
|
|
40
|
+
shutdownTelemetry: () => Promise<void>;
|
|
41
|
+
}
|
|
42
|
+
export declare function parseShutdownDrainTimeoutMs(raw: string | undefined): number;
|
|
43
|
+
export declare function parseShutdownCleanupTimeoutMs(raw: string | undefined): number;
|
|
44
|
+
/**
|
|
45
|
+
* Stops new agent work, drains tracked requests and SSE response bodies, and then
|
|
46
|
+
* releases server resources.
|
|
47
|
+
*/
|
|
48
|
+
export declare function gracefullyShutdownProductionServerWithDependencies(options: GracefulProductionShutdownOptions, dependencies: GracefulProductionShutdownDependencies): Promise<boolean>;
|
|
49
|
+
/**
|
|
50
|
+
* Enter lame-duck mode, mark readiness false, drain tracked requests and SSE
|
|
51
|
+
* response bodies, and stop a production server process.
|
|
52
|
+
*
|
|
53
|
+
* This is a one-shot, process-level lifecycle. Call it once from a SIGINT or
|
|
54
|
+
* SIGTERM handler. The function returns `true` when every tracked request drains
|
|
55
|
+
* before the timeout and `false` when cleanup continues after the timeout.
|
|
56
|
+
*/
|
|
57
|
+
export declare function gracefullyShutdownProductionServer(options: GracefulProductionShutdownOptions): Promise<boolean>;
|
|
58
|
+
export {};
|
|
59
|
+
//# sourceMappingURL=graceful-shutdown.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graceful-shutdown.d.ts","sourceRoot":"","sources":["../../../src/src/server/graceful-shutdown.ts"],"names":[],"mappings":"AAMA,8FAA8F;AAC9F,eAAO,MAAM,iCAAiC,QAAS,CAAC;AACxD,qFAAqF;AACrF,eAAO,MAAM,mCAAmC,OAAQ,CAAC;AAEzD,UAAU,8BAA8B;IACtC,gBAAgB,IAAI,MAAM,CAAC;IAC3B,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAClD,QAAQ,IAAI,IAAI,CAAC;CAClB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,iCAAiC;IAChD,uDAAuD;IACvD,MAAM,EAAE,QAAQ,GAAG,SAAS,CAAC;IAC7B,+EAA+E;IAC/E,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,4EAA4E;IAC5E,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,wEAAwE;IACxE,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,wCAAwC;IACxC,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,sEAAsE;IACtE,OAAO,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,sDAAsD;IACtD,MAAM,EAAE;QACN,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;QAC/D,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;KAChD,CAAC;CACH;AAID,UAAU,sCAAsC;IAC9C,sBAAsB,EAAE,MAAM,IAAI,CAAC;IACnC,oBAAoB,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IAC/C,cAAc,EAAE,8BAA8B,CAAC;IAC/C,iBAAiB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CACxC;AASD,wBAAgB,2BAA2B,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAE3E;AAED,wBAAgB,6BAA6B,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAE7E;AAgED;;;GAGG;AACH,wBAAsB,kDAAkD,CACtE,OAAO,EAAE,iCAAiC,EAC1C,YAAY,EAAE,sCAAsC,GACnD,OAAO,CAAC,OAAO,CAAC,CAsElB;AAED;;;;;;;GAOG;AACH,wBAAgB,kCAAkC,CAChD,OAAO,EAAE,iCAAiC,GACzC,OAAO,CAAC,OAAO,CAAC,CAElB"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { shutdownOTLP } from "../observability/tracing/otlp-setup.js";
|
|
2
|
+
import { getEnv } from "../platform/compat/process.js";
|
|
3
|
+
import { setServerInitialized } from "./handlers/monitoring/health.handler.js";
|
|
4
|
+
import { requestTracker } from "./runtime-handler/request-tracker.js";
|
|
5
|
+
import { markServerShuttingDown } from "./shutdown-state.js";
|
|
6
|
+
/** Default drain timeout leaves headroom under Kubernetes' default 30 second grace period. */
|
|
7
|
+
export const DEFAULT_SHUTDOWN_DRAIN_TIMEOUT_MS = 25_000;
|
|
8
|
+
/** Cleanup timeout keeps total shutdown below the default 30 second grace period. */
|
|
9
|
+
export const DEFAULT_SHUTDOWN_CLEANUP_TIMEOUT_MS = 4_000;
|
|
10
|
+
const defaultDependencies = {
|
|
11
|
+
markServerShuttingDown,
|
|
12
|
+
setServerInitialized,
|
|
13
|
+
requestTracker,
|
|
14
|
+
shutdownTelemetry: shutdownOTLP,
|
|
15
|
+
};
|
|
16
|
+
export function parseShutdownDrainTimeoutMs(raw) {
|
|
17
|
+
return parseShutdownTimeoutMs(raw, DEFAULT_SHUTDOWN_DRAIN_TIMEOUT_MS);
|
|
18
|
+
}
|
|
19
|
+
export function parseShutdownCleanupTimeoutMs(raw) {
|
|
20
|
+
return parseShutdownTimeoutMs(raw, DEFAULT_SHUTDOWN_CLEANUP_TIMEOUT_MS);
|
|
21
|
+
}
|
|
22
|
+
function parseShutdownTimeoutMs(raw, fallback) {
|
|
23
|
+
if (raw === undefined || raw.trim() === "")
|
|
24
|
+
return fallback;
|
|
25
|
+
const parsed = Number(raw);
|
|
26
|
+
return Number.isInteger(parsed) && parsed >= 0 ? parsed : fallback;
|
|
27
|
+
}
|
|
28
|
+
function normalizeShutdownTimeoutMs(value, fallback) {
|
|
29
|
+
if (value === undefined)
|
|
30
|
+
return fallback;
|
|
31
|
+
return Number.isInteger(value) && value >= 0 ? value : fallback;
|
|
32
|
+
}
|
|
33
|
+
async function runCleanupStep(description, action, logger, cleanupDeadlineMs) {
|
|
34
|
+
let result;
|
|
35
|
+
try {
|
|
36
|
+
result = action();
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
logger.warn(`Failed to ${description} during graceful shutdown`, { error });
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
if (!result || typeof result.then !== "function")
|
|
43
|
+
return;
|
|
44
|
+
const actionPromise = Promise.resolve(result);
|
|
45
|
+
const remainingMs = Math.max(0, cleanupDeadlineMs - Date.now());
|
|
46
|
+
if (remainingMs === 0) {
|
|
47
|
+
logger.warn("Graceful shutdown cleanup deadline exceeded", { step: description });
|
|
48
|
+
void actionPromise.catch((error) => {
|
|
49
|
+
logger.warn(`Failed to ${description} after cleanup deadline exceeded`, { error });
|
|
50
|
+
});
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
let timeoutId;
|
|
54
|
+
const outcome = await Promise.race([
|
|
55
|
+
actionPromise.then(() => ({ status: "completed" }), (error) => ({ status: "failed", error })),
|
|
56
|
+
new Promise((resolve) => {
|
|
57
|
+
timeoutId = setTimeout(() => resolve({ status: "timeout" }), remainingMs);
|
|
58
|
+
}),
|
|
59
|
+
]);
|
|
60
|
+
if (timeoutId !== undefined)
|
|
61
|
+
clearTimeout(timeoutId);
|
|
62
|
+
if (outcome.status === "failed") {
|
|
63
|
+
logger.warn(`Failed to ${description} during graceful shutdown`, { error: outcome.error });
|
|
64
|
+
}
|
|
65
|
+
else if (outcome.status === "timeout") {
|
|
66
|
+
logger.warn("Graceful shutdown cleanup deadline exceeded", { step: description });
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Stops new agent work, drains tracked requests and SSE response bodies, and then
|
|
71
|
+
* releases server resources.
|
|
72
|
+
*/
|
|
73
|
+
export async function gracefullyShutdownProductionServerWithDependencies(options, dependencies) {
|
|
74
|
+
const { logger } = options;
|
|
75
|
+
const drainTimeoutMs = normalizeShutdownTimeoutMs(options.drainTimeoutMs, parseShutdownDrainTimeoutMs(getEnv("SHUTDOWN_DRAIN_TIMEOUT_MS")));
|
|
76
|
+
const cleanupTimeoutMs = normalizeShutdownTimeoutMs(options.cleanupTimeoutMs, parseShutdownCleanupTimeoutMs(getEnv("SHUTDOWN_CLEANUP_TIMEOUT_MS")));
|
|
77
|
+
logger.info(`Received ${options.signal}, initiating graceful shutdown...`, {
|
|
78
|
+
inFlightRequests: dependencies.requestTracker.getInFlightCount(),
|
|
79
|
+
drainTimeoutMs,
|
|
80
|
+
cleanupTimeoutMs,
|
|
81
|
+
});
|
|
82
|
+
dependencies.markServerShuttingDown();
|
|
83
|
+
dependencies.setServerInitialized(false);
|
|
84
|
+
logger.info("Server marked as not ready, waiting for in-flight requests to drain...");
|
|
85
|
+
let drained = false;
|
|
86
|
+
try {
|
|
87
|
+
drained = await dependencies.requestTracker.waitForDrain(drainTimeoutMs);
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
logger.warn("Failed while waiting for in-flight requests to drain", { error });
|
|
91
|
+
}
|
|
92
|
+
if (!drained) {
|
|
93
|
+
logger.warn("Drain timeout exceeded, forcing shutdown", {
|
|
94
|
+
remainingRequests: dependencies.requestTracker.getInFlightCount(),
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
const cleanupDeadlineMs = Date.now() + cleanupTimeoutMs;
|
|
98
|
+
await runCleanupStep("stop request tracking", () => dependencies.requestTracker.shutdown(), logger, cleanupDeadlineMs);
|
|
99
|
+
if (options.dispose) {
|
|
100
|
+
await runCleanupStep("dispose the production bootstrap", options.dispose, logger, cleanupDeadlineMs);
|
|
101
|
+
}
|
|
102
|
+
await runCleanupStep("abort the production server", options.abort, logger, cleanupDeadlineMs);
|
|
103
|
+
await runCleanupStep("stop the production server", options.stop, logger, cleanupDeadlineMs);
|
|
104
|
+
await runCleanupStep("shut down telemetry", dependencies.shutdownTelemetry, logger, cleanupDeadlineMs);
|
|
105
|
+
logger.info("Graceful shutdown complete");
|
|
106
|
+
return drained;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Enter lame-duck mode, mark readiness false, drain tracked requests and SSE
|
|
110
|
+
* response bodies, and stop a production server process.
|
|
111
|
+
*
|
|
112
|
+
* This is a one-shot, process-level lifecycle. Call it once from a SIGINT or
|
|
113
|
+
* SIGTERM handler. The function returns `true` when every tracked request drains
|
|
114
|
+
* before the timeout and `false` when cleanup continues after the timeout.
|
|
115
|
+
*/
|
|
116
|
+
export function gracefullyShutdownProductionServer(options) {
|
|
117
|
+
return gracefullyShutdownProductionServerWithDependencies(options, defaultDependencies);
|
|
118
|
+
}
|
|
@@ -24,6 +24,7 @@ import "../../_dnt.polyfills.js";
|
|
|
24
24
|
import { DevServer, type DevServerOptions, type FileWatcherMetrics, type RouteDirectory, startDevServer } from "./dev-server.js";
|
|
25
25
|
import { type DiscoveryOptions, type ServerHandle, startProductionServer, type StartProductionServerOptions } from "./production-server.js";
|
|
26
26
|
export { DevServer, startDevServer, startProductionServer };
|
|
27
|
+
export { gracefullyShutdownProductionServer, type GracefulProductionShutdownOptions, } from "./graceful-shutdown.js";
|
|
27
28
|
export { createVeryfrontServer, type CreateVeryfrontServerOptions, type NodeVeryfrontServiceServer, startNodeVeryfrontServer, type StartNodeVeryfrontServerOptions, startVeryfrontServer, type StartVeryfrontServerOptions, type VeryfrontServiceServer, type VeryfrontServiceServerFetch, type VeryfrontServiceServerLogger, type VeryfrontServiceServerModule, type VeryfrontServiceServerModuleResponse, type VeryfrontServiceServerRuntime, type VeryfrontServiceServerRuntimeKind, } from "./service-server.js";
|
|
28
29
|
export type { DevServerOptions, DiscoveryOptions, FileWatcherMetrics, RouteDirectory, ServerHandle, StartProductionServerOptions, };
|
|
29
30
|
import { ReloadNotifier } from "./reload-notifier.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/src/server/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/src/server/index.ts"],"names":[],"mappings":"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"}
|
package/esm/src/server/index.js
CHANGED
|
@@ -35,6 +35,7 @@ import { HMR_MAX_MESSAGES_PER_MINUTE } from "../utils/index.js";
|
|
|
35
35
|
/** Default server port when no port is specified */
|
|
36
36
|
const DEFAULT_SERVER_PORT = 3_000;
|
|
37
37
|
export { DevServer, startDevServer, startProductionServer };
|
|
38
|
+
export { gracefullyShutdownProductionServer, } from "./graceful-shutdown.js";
|
|
38
39
|
export { createVeryfrontServer, startNodeVeryfrontServer, startVeryfrontServer, } from "./service-server.js";
|
|
39
40
|
import { ReloadNotifier } from "./reload-notifier.js";
|
|
40
41
|
export { ReloadNotifier };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"production-server.d.ts","sourceRoot":"","sources":["../../../src/src/server/production-server.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"production-server.d.ts","sourceRoot":"","sources":["../../../src/src/server/production-server.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAGnE,OAAO,EAAiB,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AA4BrE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AA4EtE,sEAAsE;AACtE,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,iBAAiB,CAAC;IAC9B,qEAAqE;IACrE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kEAAkE;IAClE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,UAAU,aAAa;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,2DAA2D;IAC3D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,sFAAsF;IACtF,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,oFAAoF;IACpF,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,8FAA8F;IAC9F,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,uGAAuG;IACvG,kBAAkB,CAAC,EAAE,SAAS,GAAG,YAAY,CAAC;IAC9C;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAClE,oFAAoF;IACpF,eAAe,CAAC,EAAE,gBAAgB,CAAC;IACnC,sFAAsF;IACtF,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACxC;AAED,6CAA6C;AAC7C,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IACrB,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3B;AAED,mDAAmD;AACnD,MAAM,WAAW,4BAA6B,SAAQ,aAAa;IACjE,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,8FAA8F;IAC9F,eAAe,CAAC,EAAE,eAAe,CAAC;CACnC;AAED,gCAAgC;AAChC,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,4BAA4B,GACpC,OAAO,CAAC,YAAY,CAAC,CA4JvB"}
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { serverLogger as logger } from "../utils/index.js";
|
|
2
2
|
import { runtime } from "../platform/adapters/detect.js";
|
|
3
3
|
import { createVeryfrontHandler } from "./runtime-handler/index.js";
|
|
4
|
-
import { requestTracker } from "./runtime-handler/request-tracker.js";
|
|
5
4
|
import { bootstrapProd } from "./bootstrap.js";
|
|
6
5
|
import { cwd, onGlobalError, onSignal } from "../platform/compat/process.js";
|
|
7
6
|
import { isDebugEnabled } from "../utils/constants/env.js";
|
|
8
|
-
import { initializeOTLPWithApis,
|
|
7
|
+
import { initializeOTLPWithApis, withSpan } from "../observability/tracing/otlp-setup.js";
|
|
9
8
|
import { startConfiguredMemoryMonitoring, stopMemoryMonitoring, } from "../utils/memory/index.js";
|
|
10
9
|
import { initializeDistributedCaches } from "../cache/distributed-cache-init.js";
|
|
11
10
|
import { defaultDistributedCacheInitializers } from "./distributed-cache-initializers.js";
|
|
@@ -14,13 +13,10 @@ import { resolveStyleContentVersion } from "../html/styles-builder/content-versi
|
|
|
14
13
|
import { buildPreparedCSSArtifactFromFiles, collectLocalProjectSourceFiles, readLocalProjectStylesheet, } from "../html/styles-builder/css-pregeneration.js";
|
|
15
14
|
import { createStyleScopeProfile } from "../html/styles-builder/style-scope-profile.js";
|
|
16
15
|
import { setServerInitialized } from "./handlers/monitoring/health.handler.js";
|
|
17
|
-
import {
|
|
16
|
+
import { gracefullyShutdownProductionServer, parseShutdownDrainTimeoutMs, } from "./graceful-shutdown.js";
|
|
18
17
|
import { enableSSRClientOnlyFetching, enableSSRFetchInterception, setSSRServerPort, } from "../rendering/ssr-globals.js";
|
|
19
18
|
const serverLog = logger.component("server");
|
|
20
19
|
const globalLog = logger.component("global");
|
|
21
|
-
/** Default time to wait for in-flight requests to drain during shutdown.
|
|
22
|
-
* K8s default terminationGracePeriodSeconds is 30s, so 25s leaves headroom. */
|
|
23
|
-
const DEFAULT_SHUTDOWN_DRAIN_TIMEOUT_MS = 25_000;
|
|
24
20
|
/** Default port when PORT / VERYFRONT_PORT env vars are not set */
|
|
25
21
|
const DEFAULT_SERVER_PORT = 3_000;
|
|
26
22
|
async function prewarmLocalProductionCSSArtifacts(adapter, options) {
|
|
@@ -266,43 +262,20 @@ if (globalThis[Symbol.for("import-meta-ponyfill-esmodule")](import.meta).main) {
|
|
|
266
262
|
logger.info("Server fully initialized, ready to accept traffic");
|
|
267
263
|
// Graceful shutdown for direct CLI execution (e.g., deno run)
|
|
268
264
|
// Default drain timeout: 25 seconds (K8s default terminationGracePeriodSeconds is 30)
|
|
269
|
-
const drainTimeoutMs =
|
|
265
|
+
const drainTimeoutMs = parseShutdownDrainTimeoutMs(adapter.env.get("SHUTDOWN_DRAIN_TIMEOUT_MS"));
|
|
270
266
|
let shuttingDown = false;
|
|
271
267
|
const shutdown = async (signal) => {
|
|
272
268
|
if (shuttingDown)
|
|
273
269
|
return;
|
|
274
270
|
shuttingDown = true;
|
|
275
|
-
|
|
276
|
-
|
|
271
|
+
await gracefullyShutdownProductionServer({
|
|
272
|
+
signal,
|
|
277
273
|
drainTimeoutMs,
|
|
274
|
+
abort: () => shutdownController.abort(),
|
|
275
|
+
dispose: bootstrap.dispose,
|
|
276
|
+
stop: server.stop,
|
|
277
|
+
logger,
|
|
278
278
|
});
|
|
279
|
-
// Phase 1: Enter lame-duck mode. markServerShuttingDown() makes the
|
|
280
|
-
// agent-work handlers reject NEW requests with 503 (before any side
|
|
281
|
-
// effects) so the API can retry against another instance, even while the
|
|
282
|
-
// pod IP is still directly reachable. setServerInitialized(false) flips
|
|
283
|
-
// /readyz to not-ready so K8s stops routing Service traffic.
|
|
284
|
-
markServerShuttingDown();
|
|
285
|
-
setServerInitialized(false);
|
|
286
|
-
logger.info("Server marked as not ready, waiting for in-flight requests to drain...");
|
|
287
|
-
try {
|
|
288
|
-
// Phase 2: Wait for in-flight requests to complete (graceful drain)
|
|
289
|
-
const drained = await requestTracker.waitForDrain(drainTimeoutMs);
|
|
290
|
-
if (!drained) {
|
|
291
|
-
logger.warn("Drain timeout exceeded, forcing shutdown", {
|
|
292
|
-
remainingRequests: requestTracker.getInFlightCount(),
|
|
293
|
-
});
|
|
294
|
-
}
|
|
295
|
-
// Phase 3: Stop accepting new connections and clean up
|
|
296
|
-
requestTracker.shutdown();
|
|
297
|
-
await bootstrap.dispose?.();
|
|
298
|
-
shutdownController.abort();
|
|
299
|
-
await server.stop();
|
|
300
|
-
await shutdownOTLP();
|
|
301
|
-
logger.info("Graceful shutdown complete");
|
|
302
|
-
}
|
|
303
|
-
catch (error) {
|
|
304
|
-
logger.warn("Error while shutting down production server:", error);
|
|
305
|
-
}
|
|
306
279
|
};
|
|
307
280
|
const handleSignal = (signal) => {
|
|
308
281
|
void shutdown(signal).catch((error) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "veryfront",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1055",
|
|
4
4
|
"description": "The simplest way to build AI-powered apps",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react",
|
|
@@ -328,10 +328,10 @@
|
|
|
328
328
|
"@types/react": "19.2.14",
|
|
329
329
|
"@types/react-dom": "19.2.3",
|
|
330
330
|
"ws": "8.21.0",
|
|
331
|
-
"@veryfront/ext-bundler-esbuild": "0.1.
|
|
332
|
-
"@veryfront/ext-content-mdx": "0.1.
|
|
333
|
-
"@veryfront/ext-css-tailwind": "0.1.
|
|
334
|
-
"@veryfront/ext-parser-babel": "0.1.
|
|
331
|
+
"@veryfront/ext-bundler-esbuild": "0.1.1055",
|
|
332
|
+
"@veryfront/ext-content-mdx": "0.1.1055",
|
|
333
|
+
"@veryfront/ext-css-tailwind": "0.1.1055",
|
|
334
|
+
"@veryfront/ext-parser-babel": "0.1.1055"
|
|
335
335
|
},
|
|
336
336
|
"devDependencies": {
|
|
337
337
|
"@types/node": "20.9.0"
|