veryfront 0.1.583 → 0.1.585
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/deno.js +1 -1
- package/esm/src/server/production-server.d.ts.map +1 -1
- package/esm/src/server/production-server.js +105 -112
- package/esm/src/utils/memory/index.d.ts +1 -1
- package/esm/src/utils/memory/index.d.ts.map +1 -1
- package/esm/src/utils/memory/index.js +1 -1
- package/esm/src/utils/memory/profiler.d.ts +16 -0
- package/esm/src/utils/memory/profiler.d.ts.map +1 -1
- package/esm/src/utils/memory/profiler.js +33 -1
- package/esm/src/utils/version-constant.d.ts +1 -1
- package/esm/src/utils/version-constant.js +1 -1
- package/package.json +1 -1
package/esm/deno.js
CHANGED
|
@@ -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;AAInE,OAAO,EAAiB,KAAK,eAAe,EAAE,MAAM,gBAAgB,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;AAInE,OAAO,EAAiB,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AA2BrE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAgFtE,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,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,CA0JvB"}
|
|
@@ -6,7 +6,7 @@ import { bootstrapProd } from "./bootstrap.js";
|
|
|
6
6
|
import { cwd, onGlobalError, onSignal } from "../platform/compat/process.js";
|
|
7
7
|
import { isDebugEnabled } from "../utils/constants/env.js";
|
|
8
8
|
import { initializeOTLPWithApis, shutdownOTLP, withSpan, } from "../observability/tracing/otlp-setup.js";
|
|
9
|
-
import {
|
|
9
|
+
import { startConfiguredMemoryMonitoring, stopMemoryMonitoring, } from "../utils/memory/index.js";
|
|
10
10
|
import { initializeDistributedCaches } from "../cache/distributed-cache-init.js";
|
|
11
11
|
import { getConfig } from "../config/index.js";
|
|
12
12
|
import { resolveStyleContentVersion } from "../html/styles-builder/content-version.js";
|
|
@@ -16,8 +16,6 @@ import { setServerInitialized } from "./handlers/monitoring/health.handler.js";
|
|
|
16
16
|
import { enableSSRClientOnlyFetching, enableSSRFetchInterception, setSSRServerPort, } from "../rendering/ssr-globals.js";
|
|
17
17
|
const serverLog = logger.component("server");
|
|
18
18
|
const globalLog = logger.component("global");
|
|
19
|
-
/** Default interval for periodic memory usage snapshots */
|
|
20
|
-
const DEFAULT_MEMORY_MONITORING_INTERVAL_MS = 30_000;
|
|
21
19
|
/** Default time to wait for in-flight requests to drain during shutdown.
|
|
22
20
|
* K8s default terminationGracePeriodSeconds is 30s, so 25s leaves headroom. */
|
|
23
21
|
const DEFAULT_SHUTDOWN_DRAIN_TIMEOUT_MS = 25_000;
|
|
@@ -82,105 +80,116 @@ export function startProductionServer(options) {
|
|
|
82
80
|
return withSpan("server.startProductionServer", async () => {
|
|
83
81
|
const { projectDir, port, bindAddress = "0.0.0.0", signal, debug, defaultProjectSlug, defaultProjectId, defaultEnvironment, requestInterceptor, bootstrapResult, discoveryConfig, localProjects, } = options;
|
|
84
82
|
const baseAdapter = options.adapter ?? (await runtime.get());
|
|
85
|
-
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
83
|
+
const memoryMonitoringConfig = startConfiguredMemoryMonitoring(baseAdapter.env);
|
|
84
|
+
const ownsMemoryMonitoring = memoryMonitoringConfig.enabled;
|
|
85
|
+
try {
|
|
86
|
+
// Use pre-computed bootstrap result if provided, otherwise bootstrap here
|
|
87
|
+
const bootstrap = bootstrapResult ?? await bootstrapProd(projectDir, baseAdapter);
|
|
88
|
+
const adapter = bootstrap.adapter;
|
|
89
|
+
if (bootstrap.usingFSAdapter) {
|
|
90
|
+
logger.debug("FSAdapter initialized", { type: bootstrap.fsAdapterType });
|
|
91
|
+
}
|
|
92
|
+
await prewarmLocalProductionCSSArtifacts(bootstrap.adapter, {
|
|
93
|
+
projectDir,
|
|
94
|
+
defaultProjectSlug,
|
|
95
|
+
defaultProjectId,
|
|
96
|
+
defaultEnvironment,
|
|
97
|
+
localProjects,
|
|
98
|
+
});
|
|
99
|
+
// Enable SSR fetch interception to handle relative URLs during SSR
|
|
100
|
+
setSSRServerPort(port);
|
|
101
|
+
enableSSRFetchInterception();
|
|
102
|
+
// Enable client-only fetching for /api/* routes in production.
|
|
103
|
+
// This returns empty mock responses during SSR (instead of failing with
|
|
104
|
+
// "Invalid URL" or "Connection refused"). React Query will refetch
|
|
105
|
+
// the actual data client-side after hydration.
|
|
106
|
+
enableSSRClientOnlyFetching();
|
|
107
|
+
// Run primitive discovery before serving (registries must be populated before first request)
|
|
108
|
+
if (discoveryConfig) {
|
|
109
|
+
try {
|
|
110
|
+
const { discoverAll } = await import("../discovery/index.js");
|
|
111
|
+
const { isExtendedFSAdapter } = await import("../platform/adapters/fs/wrapper.js");
|
|
112
|
+
if (discoveryConfig.projectSlug && discoveryConfig.apiToken &&
|
|
113
|
+
discoveryConfig.fsAdapter && isExtendedFSAdapter(discoveryConfig.fsAdapter) &&
|
|
114
|
+
discoveryConfig.fsAdapter.isMultiProjectMode()) {
|
|
115
|
+
// Multi-project proxy: scope discovery to specific project
|
|
116
|
+
await discoveryConfig.fsAdapter.runWithContext(discoveryConfig.projectSlug, discoveryConfig.apiToken, () => discoverAll({
|
|
117
|
+
baseDir: discoveryConfig.baseDir,
|
|
118
|
+
fsAdapter: discoveryConfig.fsAdapter,
|
|
119
|
+
verbose: discoveryConfig.verbose ?? false,
|
|
120
|
+
}));
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
await discoverAll({
|
|
124
|
+
baseDir: discoveryConfig.baseDir,
|
|
125
|
+
fsAdapter: discoveryConfig.fsAdapter,
|
|
126
|
+
verbose: discoveryConfig.verbose ?? false,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
120
129
|
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
fsAdapter: discoveryConfig.fsAdapter,
|
|
125
|
-
verbose: discoveryConfig.verbose ?? false,
|
|
130
|
+
catch (error) {
|
|
131
|
+
serverLog.error("Primitive discovery failed", {
|
|
132
|
+
error: error instanceof Error ? error.message : String(error),
|
|
126
133
|
});
|
|
127
134
|
}
|
|
128
135
|
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
136
|
+
logger.info("Starting production server", { projectDir, port, bindAddress });
|
|
137
|
+
const baseHandler = createVeryfrontHandler(projectDir, adapter, {
|
|
138
|
+
projectDir,
|
|
139
|
+
debug,
|
|
140
|
+
config: bootstrap.config,
|
|
141
|
+
defaultProjectSlug,
|
|
142
|
+
defaultProjectId,
|
|
143
|
+
defaultEnvironment,
|
|
144
|
+
localProjects,
|
|
145
|
+
});
|
|
146
|
+
// Wrap handler with interceptor if provided (for combined mode)
|
|
147
|
+
// WebSocket upgrade requests MUST NOT be intercepted because the interceptor
|
|
148
|
+
// creates a new Request object, which breaks Deno.upgradeWebSocket()
|
|
149
|
+
const handler = requestInterceptor
|
|
150
|
+
? Object.assign(async (req) => {
|
|
151
|
+
const isWebSocketUpgrade = req.headers.get("upgrade")?.toLowerCase() === "websocket";
|
|
152
|
+
if (isWebSocketUpgrade)
|
|
153
|
+
return baseHandler(req);
|
|
154
|
+
return baseHandler(await requestInterceptor(req));
|
|
155
|
+
}, { ready: baseHandler.ready })
|
|
156
|
+
: baseHandler;
|
|
157
|
+
let resolveListenReady;
|
|
158
|
+
const listenReady = new Promise((resolve) => {
|
|
159
|
+
resolveListenReady = resolve;
|
|
160
|
+
});
|
|
161
|
+
const ready = (async () => {
|
|
162
|
+
await Promise.all([listenReady, handler.ready ?? Promise.resolve()]);
|
|
163
|
+
// Mark server as initialized when ready resolves
|
|
164
|
+
setServerInitialized(true);
|
|
165
|
+
})();
|
|
166
|
+
const server = await adapter.serve(handler, {
|
|
167
|
+
port,
|
|
168
|
+
hostname: bindAddress, // Deno uses "hostname" for bind address
|
|
169
|
+
signal,
|
|
170
|
+
onListen: (params) => {
|
|
171
|
+
resolveListenReady?.();
|
|
172
|
+
logger.info("Production server listening", params);
|
|
173
|
+
},
|
|
174
|
+
});
|
|
175
|
+
const stop = async () => {
|
|
176
|
+
setServerInitialized(false);
|
|
177
|
+
if (ownsMemoryMonitoring)
|
|
178
|
+
stopMemoryMonitoring();
|
|
179
|
+
try {
|
|
180
|
+
await server.stop();
|
|
181
|
+
}
|
|
182
|
+
catch (error) {
|
|
183
|
+
logger.debug("Server stop failed", { error });
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
return { ready, stop };
|
|
134
187
|
}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
config: bootstrap.config,
|
|
140
|
-
defaultProjectSlug,
|
|
141
|
-
defaultProjectId,
|
|
142
|
-
defaultEnvironment,
|
|
143
|
-
localProjects,
|
|
144
|
-
});
|
|
145
|
-
// Wrap handler with interceptor if provided (for combined mode)
|
|
146
|
-
// WebSocket upgrade requests MUST NOT be intercepted because the interceptor
|
|
147
|
-
// creates a new Request object, which breaks Deno.upgradeWebSocket()
|
|
148
|
-
const handler = requestInterceptor
|
|
149
|
-
? Object.assign(async (req) => {
|
|
150
|
-
const isWebSocketUpgrade = req.headers.get("upgrade")?.toLowerCase() === "websocket";
|
|
151
|
-
if (isWebSocketUpgrade)
|
|
152
|
-
return baseHandler(req);
|
|
153
|
-
return baseHandler(await requestInterceptor(req));
|
|
154
|
-
}, { ready: baseHandler.ready })
|
|
155
|
-
: baseHandler;
|
|
156
|
-
let resolveListenReady;
|
|
157
|
-
const listenReady = new Promise((resolve) => {
|
|
158
|
-
resolveListenReady = resolve;
|
|
159
|
-
});
|
|
160
|
-
const ready = (async () => {
|
|
161
|
-
await Promise.all([listenReady, handler.ready ?? Promise.resolve()]);
|
|
162
|
-
// Mark server as initialized when ready resolves
|
|
163
|
-
setServerInitialized(true);
|
|
164
|
-
})();
|
|
165
|
-
const server = await adapter.serve(handler, {
|
|
166
|
-
port,
|
|
167
|
-
hostname: bindAddress, // Deno uses "hostname" for bind address
|
|
168
|
-
signal,
|
|
169
|
-
onListen: (params) => {
|
|
170
|
-
resolveListenReady?.();
|
|
171
|
-
logger.info("Production server listening", params);
|
|
172
|
-
},
|
|
173
|
-
});
|
|
174
|
-
async function stop() {
|
|
175
|
-
setServerInitialized(false);
|
|
176
|
-
try {
|
|
177
|
-
await server.stop();
|
|
178
|
-
}
|
|
179
|
-
catch (error) {
|
|
180
|
-
logger.debug("Server stop failed", { error });
|
|
181
|
-
}
|
|
188
|
+
catch (error) {
|
|
189
|
+
if (ownsMemoryMonitoring)
|
|
190
|
+
stopMemoryMonitoring();
|
|
191
|
+
throw error;
|
|
182
192
|
}
|
|
183
|
-
return { ready, stop };
|
|
184
193
|
}, { "server.port": options.port, "server.bindAddress": options.bindAddress ?? "0.0.0.0" });
|
|
185
194
|
}
|
|
186
195
|
if (globalThis[Symbol.for("import-meta-ponyfill-esmodule")](import.meta).main) {
|
|
@@ -224,21 +233,6 @@ if (globalThis[Symbol.for("import-meta-ponyfill-esmodule")](import.meta).main) {
|
|
|
224
233
|
});
|
|
225
234
|
}
|
|
226
235
|
const adapter = await runtime.get();
|
|
227
|
-
// Start memory monitoring if enabled
|
|
228
|
-
const enableMemoryMonitoring = adapter.env.get("ENABLE_MEMORY_MONITORING") === "true";
|
|
229
|
-
const monitoringIntervalMs = parseInt(adapter.env.get("MEMORY_MONITORING_INTERVAL_MS") ??
|
|
230
|
-
String(DEFAULT_MEMORY_MONITORING_INTERVAL_MS), 10);
|
|
231
|
-
if (enableMemoryMonitoring) {
|
|
232
|
-
startMemoryMonitoring(monitoringIntervalMs);
|
|
233
|
-
logger.debug("Memory monitoring enabled", { intervalMs: monitoringIntervalMs });
|
|
234
|
-
// Log initial memory state
|
|
235
|
-
const initialSnapshot = getMemorySnapshot();
|
|
236
|
-
logger.debug("Initial memory state", {
|
|
237
|
-
heapUsedMB: initialSnapshot.heap.usedHeapSizeMB,
|
|
238
|
-
heapLimitMB: initialSnapshot.heap.heapSizeLimitMB,
|
|
239
|
-
cacheCount: initialSnapshot.caches.length,
|
|
240
|
-
});
|
|
241
|
-
}
|
|
242
236
|
const shutdownController = new AbortController();
|
|
243
237
|
const projectDir = cwd();
|
|
244
238
|
const port = Number(adapter.env.get("PORT") ?? adapter.env.get("VERYFRONT_PORT") ?? DEFAULT_SERVER_PORT);
|
|
@@ -284,7 +278,6 @@ if (globalThis[Symbol.for("import-meta-ponyfill-esmodule")](import.meta).main) {
|
|
|
284
278
|
});
|
|
285
279
|
}
|
|
286
280
|
// Phase 3: Stop accepting new connections and clean up
|
|
287
|
-
stopMemoryMonitoring();
|
|
288
281
|
requestTracker.shutdown();
|
|
289
282
|
await bootstrap.dispose?.();
|
|
290
283
|
shutdownController.abort();
|
|
@@ -3,5 +3,5 @@
|
|
|
3
3
|
*
|
|
4
4
|
* @module utils/memory
|
|
5
5
|
*/
|
|
6
|
-
export { type CacheStats, checkMemoryPressure, clearAllCaches, forceGC, type GCStats, getCacheStats, getHeapStats, getMemoryMonitoringLogContext, getMemorySnapshot, getTopCacheStats, type HeapStats, type MemoryMonitoringLogContext, type MemorySnapshot, type MonitoringCacheStats, registerCache, setHeapWarningThreshold, startMemoryMonitoring, stopMemoryMonitoring, unregisterCache, } from "./profiler.js";
|
|
6
|
+
export { type CacheStats, checkMemoryPressure, clearAllCaches, DEFAULT_MEMORY_MONITORING_INTERVAL_MS, forceGC, type GCStats, getCacheStats, getHeapStats, getMemoryMonitoringConfig, getMemoryMonitoringLogContext, getMemoryMonitoringState, getMemorySnapshot, getTopCacheStats, type HeapStats, type MemoryMonitoringConfig, type MemoryMonitoringEnv, type MemoryMonitoringLogContext, type MemoryMonitoringState, type MemorySnapshot, type MonitoringCacheStats, registerCache, setHeapWarningThreshold, startConfiguredMemoryMonitoring, startMemoryMonitoring, stopMemoryMonitoring, unregisterCache, } from "./profiler.js";
|
|
7
7
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/src/utils/memory/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,KAAK,UAAU,EACf,mBAAmB,EACnB,cAAc,EACd,OAAO,EACP,KAAK,OAAO,EACZ,aAAa,EACb,YAAY,EACZ,6BAA6B,EAC7B,iBAAiB,EACjB,gBAAgB,EAChB,KAAK,SAAS,EACd,KAAK,0BAA0B,EAC/B,KAAK,cAAc,EACnB,KAAK,oBAAoB,EACzB,aAAa,EACb,uBAAuB,EACvB,qBAAqB,EACrB,oBAAoB,EACpB,eAAe,GAChB,MAAM,eAAe,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/src/utils/memory/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,KAAK,UAAU,EACf,mBAAmB,EACnB,cAAc,EACd,qCAAqC,EACrC,OAAO,EACP,KAAK,OAAO,EACZ,aAAa,EACb,YAAY,EACZ,yBAAyB,EACzB,6BAA6B,EAC7B,wBAAwB,EACxB,iBAAiB,EACjB,gBAAgB,EAChB,KAAK,SAAS,EACd,KAAK,sBAAsB,EAC3B,KAAK,mBAAmB,EACxB,KAAK,0BAA0B,EAC/B,KAAK,qBAAqB,EAC1B,KAAK,cAAc,EACnB,KAAK,oBAAoB,EACzB,aAAa,EACb,uBAAuB,EACvB,+BAA+B,EAC/B,qBAAqB,EACrB,oBAAoB,EACpB,eAAe,GAChB,MAAM,eAAe,CAAC"}
|
|
@@ -3,4 +3,4 @@
|
|
|
3
3
|
*
|
|
4
4
|
* @module utils/memory
|
|
5
5
|
*/
|
|
6
|
-
export { checkMemoryPressure, clearAllCaches, forceGC, getCacheStats, getHeapStats, getMemoryMonitoringLogContext, getMemorySnapshot, getTopCacheStats, registerCache, setHeapWarningThreshold, startMemoryMonitoring, stopMemoryMonitoring, unregisterCache, } from "./profiler.js";
|
|
6
|
+
export { checkMemoryPressure, clearAllCaches, DEFAULT_MEMORY_MONITORING_INTERVAL_MS, forceGC, getCacheStats, getHeapStats, getMemoryMonitoringConfig, getMemoryMonitoringLogContext, getMemoryMonitoringState, getMemorySnapshot, getTopCacheStats, registerCache, setHeapWarningThreshold, startConfiguredMemoryMonitoring, startMemoryMonitoring, stopMemoryMonitoring, unregisterCache, } from "./profiler.js";
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
/** Default interval for periodic memory snapshots (30 seconds) */
|
|
2
|
+
export declare const DEFAULT_MEMORY_MONITORING_INTERVAL_MS = 30000;
|
|
1
3
|
export interface CacheStats {
|
|
2
4
|
name: string;
|
|
3
5
|
entries: number;
|
|
@@ -37,6 +39,17 @@ export interface MemoryMonitoringLogContext {
|
|
|
37
39
|
totalCacheEntries: number;
|
|
38
40
|
topCaches: MonitoringCacheStats[];
|
|
39
41
|
}
|
|
42
|
+
export interface MemoryMonitoringEnv {
|
|
43
|
+
get(key: string): string | null | undefined;
|
|
44
|
+
}
|
|
45
|
+
export interface MemoryMonitoringConfig {
|
|
46
|
+
enabled: boolean;
|
|
47
|
+
intervalMs: number;
|
|
48
|
+
}
|
|
49
|
+
export interface MemoryMonitoringState {
|
|
50
|
+
active: boolean;
|
|
51
|
+
intervalMs: number | undefined;
|
|
52
|
+
}
|
|
40
53
|
export interface GCStats {
|
|
41
54
|
majorGCs: number;
|
|
42
55
|
minorGCs: number;
|
|
@@ -49,8 +62,11 @@ export declare function getCacheStats(): CacheStats[];
|
|
|
49
62
|
export declare function getMemorySnapshot(): MemorySnapshot;
|
|
50
63
|
export declare function getTopCacheStats(caches: CacheStats[], limit?: number): MonitoringCacheStats[];
|
|
51
64
|
export declare function getMemoryMonitoringLogContext(snapshot: MemorySnapshot, topCacheLimit?: number): MemoryMonitoringLogContext;
|
|
65
|
+
export declare function getMemoryMonitoringConfig(env: MemoryMonitoringEnv): MemoryMonitoringConfig;
|
|
66
|
+
export declare function getMemoryMonitoringState(): MemoryMonitoringState;
|
|
52
67
|
export declare function forceGC(): Promise<boolean>;
|
|
53
68
|
export declare function startMemoryMonitoring(intervalMs?: number): void;
|
|
69
|
+
export declare function startConfiguredMemoryMonitoring(env: MemoryMonitoringEnv): MemoryMonitoringConfig;
|
|
54
70
|
export declare function stopMemoryMonitoring(): void;
|
|
55
71
|
export declare function setHeapWarningThreshold(threshold: number): void;
|
|
56
72
|
export declare function clearAllCaches(): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"profiler.d.ts","sourceRoot":"","sources":["../../../../src/src/utils/memory/profiler.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"profiler.d.ts","sourceRoot":"","sources":["../../../../src/src/utils/memory/profiler.ts"],"names":[],"mappings":"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"}
|
|
@@ -11,11 +11,12 @@ const logger = rendererLogger.component("memory-profiler");
|
|
|
11
11
|
/** Fallback V8 heap limit when no --max-old-space-size flag is set (5 GB) */
|
|
12
12
|
const DEFAULT_HEAP_LIMIT_MB = 5_120;
|
|
13
13
|
/** Default interval for periodic memory snapshots (30 seconds) */
|
|
14
|
-
const DEFAULT_MEMORY_MONITORING_INTERVAL_MS = 30_000;
|
|
14
|
+
export const DEFAULT_MEMORY_MONITORING_INTERVAL_MS = 30_000;
|
|
15
15
|
/** Heap growth (MB) per interval that triggers a rapid-growth warning */
|
|
16
16
|
const HEAP_RAPID_GROWTH_THRESHOLD_MB = 100;
|
|
17
17
|
const cacheRegistry = new Map();
|
|
18
18
|
let memoryCheckInterval;
|
|
19
|
+
let memoryCheckIntervalMs;
|
|
19
20
|
let lastHeapUsed = 0;
|
|
20
21
|
let heapGrowthWarningThreshold = 0.8;
|
|
21
22
|
export function registerCache(name, getStats) {
|
|
@@ -109,6 +110,21 @@ export function getMemoryMonitoringLogContext(snapshot, topCacheLimit = 8) {
|
|
|
109
110
|
topCaches: getTopCacheStats(snapshot.caches, topCacheLimit),
|
|
110
111
|
};
|
|
111
112
|
}
|
|
113
|
+
export function getMemoryMonitoringConfig(env) {
|
|
114
|
+
const enabled = env.get("ENABLE_MEMORY_MONITORING") === "true";
|
|
115
|
+
const rawInterval = env.get("MEMORY_MONITORING_INTERVAL_MS");
|
|
116
|
+
const parsedInterval = parseInt(rawInterval ?? String(DEFAULT_MEMORY_MONITORING_INTERVAL_MS), 10);
|
|
117
|
+
const intervalMs = Number.isFinite(parsedInterval) && parsedInterval > 0
|
|
118
|
+
? parsedInterval
|
|
119
|
+
: DEFAULT_MEMORY_MONITORING_INTERVAL_MS;
|
|
120
|
+
return { enabled, intervalMs };
|
|
121
|
+
}
|
|
122
|
+
export function getMemoryMonitoringState() {
|
|
123
|
+
return {
|
|
124
|
+
active: memoryCheckInterval !== undefined,
|
|
125
|
+
intervalMs: memoryCheckIntervalMs,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
112
128
|
export async function forceGC() {
|
|
113
129
|
try {
|
|
114
130
|
const buffer = new Uint8Array(100 * 1024 * 1024);
|
|
@@ -125,6 +141,7 @@ export function startMemoryMonitoring(intervalMs = DEFAULT_MEMORY_MONITORING_INT
|
|
|
125
141
|
if (memoryCheckInterval)
|
|
126
142
|
clearInterval(memoryCheckInterval);
|
|
127
143
|
logger.info(`Starting memory monitoring (interval: ${intervalMs}ms)`);
|
|
144
|
+
memoryCheckIntervalMs = intervalMs;
|
|
128
145
|
memoryCheckInterval = dntShim.setInterval(() => {
|
|
129
146
|
const snapshot = getMemorySnapshot();
|
|
130
147
|
const { heap } = snapshot;
|
|
@@ -150,11 +167,26 @@ export function startMemoryMonitoring(intervalMs = DEFAULT_MEMORY_MONITORING_INT
|
|
|
150
167
|
lastHeapUsed = heap.usedHeapSizeMB;
|
|
151
168
|
}, intervalMs);
|
|
152
169
|
}
|
|
170
|
+
export function startConfiguredMemoryMonitoring(env) {
|
|
171
|
+
const config = getMemoryMonitoringConfig(env);
|
|
172
|
+
if (!config.enabled)
|
|
173
|
+
return config;
|
|
174
|
+
startMemoryMonitoring(config.intervalMs);
|
|
175
|
+
logger.info("Memory monitoring enabled", { intervalMs: config.intervalMs });
|
|
176
|
+
const initialSnapshot = getMemorySnapshot();
|
|
177
|
+
logger.info("Initial memory state", {
|
|
178
|
+
heapUsedMB: initialSnapshot.heap.usedHeapSizeMB,
|
|
179
|
+
heapLimitMB: initialSnapshot.heap.heapSizeLimitMB,
|
|
180
|
+
cacheCount: initialSnapshot.caches.length,
|
|
181
|
+
});
|
|
182
|
+
return config;
|
|
183
|
+
}
|
|
153
184
|
export function stopMemoryMonitoring() {
|
|
154
185
|
if (!memoryCheckInterval)
|
|
155
186
|
return;
|
|
156
187
|
clearInterval(memoryCheckInterval);
|
|
157
188
|
memoryCheckInterval = undefined;
|
|
189
|
+
memoryCheckIntervalMs = undefined;
|
|
158
190
|
logger.info("Memory monitoring stopped");
|
|
159
191
|
}
|
|
160
192
|
export function setHeapWarningThreshold(threshold) {
|