@platformatic/runtime 3.32.0-alpha.0 → 3.32.0-alpha.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/config.d.ts +37 -3
- package/lib/runtime.js +132 -10
- package/lib/worker/interceptors.js +20 -1
- package/lib/worker/main.js +56 -3
- package/package.json +15 -15
- package/schema.json +131 -56
package/config.d.ts
CHANGED
|
@@ -42,7 +42,6 @@ export type PlatformaticRuntimeConfig = {
|
|
|
42
42
|
maxHeapTotal?: number | string;
|
|
43
43
|
maxYoungGeneration?: number | string;
|
|
44
44
|
codeRangeSize?: number | string;
|
|
45
|
-
noHeapCheck?: boolean | string;
|
|
46
45
|
};
|
|
47
46
|
dependencies?: string[];
|
|
48
47
|
arguments?: string[];
|
|
@@ -79,6 +78,18 @@ export type PlatformaticRuntimeConfig = {
|
|
|
79
78
|
)[];
|
|
80
79
|
[k: string]: unknown;
|
|
81
80
|
};
|
|
81
|
+
compileCache?:
|
|
82
|
+
| boolean
|
|
83
|
+
| {
|
|
84
|
+
/**
|
|
85
|
+
* Enable Node.js module compile cache for faster startup
|
|
86
|
+
*/
|
|
87
|
+
enabled?: boolean;
|
|
88
|
+
/**
|
|
89
|
+
* Directory to store compile cache. Defaults to .plt/compile-cache in app root
|
|
90
|
+
*/
|
|
91
|
+
directory?: string;
|
|
92
|
+
};
|
|
82
93
|
};
|
|
83
94
|
};
|
|
84
95
|
};
|
|
@@ -109,7 +120,7 @@ export type PlatformaticRuntimeConfig = {
|
|
|
109
120
|
};
|
|
110
121
|
workersRestartDelay?: number | string;
|
|
111
122
|
logger?: {
|
|
112
|
-
level
|
|
123
|
+
level?: (
|
|
113
124
|
| ("fatal" | "error" | "warn" | "info" | "debug" | "trace" | "silent")
|
|
114
125
|
| {
|
|
115
126
|
[k: string]: unknown;
|
|
@@ -213,7 +224,6 @@ export type PlatformaticRuntimeConfig = {
|
|
|
213
224
|
maxHeapTotal?: number | string;
|
|
214
225
|
maxYoungGeneration?: number | string;
|
|
215
226
|
codeRangeSize?: number | string;
|
|
216
|
-
noHeapCheck?: boolean | string;
|
|
217
227
|
};
|
|
218
228
|
undici?: {
|
|
219
229
|
agentOptions?: {
|
|
@@ -265,6 +275,18 @@ export type PlatformaticRuntimeConfig = {
|
|
|
265
275
|
maxSize?: number;
|
|
266
276
|
maxEntrySize?: number;
|
|
267
277
|
maxCount?: number;
|
|
278
|
+
/**
|
|
279
|
+
* Whitelist of origins to cache. Supports exact strings and regex patterns (e.g., "/https:\\/\\/.*\\.example\\.com/").
|
|
280
|
+
*/
|
|
281
|
+
origins?: string[];
|
|
282
|
+
/**
|
|
283
|
+
* Default cache duration in seconds for responses without explicit expiration headers.
|
|
284
|
+
*/
|
|
285
|
+
cacheByDefault?: number;
|
|
286
|
+
/**
|
|
287
|
+
* Cache type. "shared" caches may be shared between users, "private" caches are user-specific.
|
|
288
|
+
*/
|
|
289
|
+
type?: "shared" | "private";
|
|
268
290
|
[k: string]: unknown;
|
|
269
291
|
};
|
|
270
292
|
watch?: boolean | string;
|
|
@@ -503,4 +525,16 @@ export type PlatformaticRuntimeConfig = {
|
|
|
503
525
|
[k: string]: string | [string, ...string[]];
|
|
504
526
|
};
|
|
505
527
|
};
|
|
528
|
+
compileCache?:
|
|
529
|
+
| boolean
|
|
530
|
+
| {
|
|
531
|
+
/**
|
|
532
|
+
* Enable Node.js module compile cache for faster startup
|
|
533
|
+
*/
|
|
534
|
+
enabled?: boolean;
|
|
535
|
+
/**
|
|
536
|
+
* Directory to store compile cache. Defaults to .plt/compile-cache in app root
|
|
537
|
+
*/
|
|
538
|
+
directory?: string;
|
|
539
|
+
};
|
|
506
540
|
};
|
package/lib/runtime.js
CHANGED
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
parseMemorySize
|
|
11
11
|
} from '@platformatic/foundation'
|
|
12
12
|
import { ITC } from '@platformatic/itc'
|
|
13
|
+
import { client as metricsClient, collectProcessMetrics } from '@platformatic/metrics'
|
|
13
14
|
import fastify from 'fastify'
|
|
14
15
|
import { EventEmitter, once } from 'node:events'
|
|
15
16
|
import { existsSync } from 'node:fs'
|
|
@@ -71,6 +72,21 @@ const kInspectorOptions = Symbol('plt.runtime.worker.inspectorOptions')
|
|
|
71
72
|
|
|
72
73
|
const MAX_LISTENERS_COUNT = 100
|
|
73
74
|
|
|
75
|
+
function parseOrigins (origins) {
|
|
76
|
+
if (!origins) return undefined
|
|
77
|
+
|
|
78
|
+
return origins.map(origin => {
|
|
79
|
+
// Check if the origin is a regex pattern (starts and ends with /)
|
|
80
|
+
if (origin.startsWith('/') && origin.lastIndexOf('/') > 0) {
|
|
81
|
+
const lastSlash = origin.lastIndexOf('/')
|
|
82
|
+
const pattern = origin.slice(1, lastSlash)
|
|
83
|
+
const flags = origin.slice(lastSlash + 1)
|
|
84
|
+
return new RegExp(pattern, flags)
|
|
85
|
+
}
|
|
86
|
+
return origin
|
|
87
|
+
})
|
|
88
|
+
}
|
|
89
|
+
|
|
74
90
|
const MAX_CONCURRENCY = 5
|
|
75
91
|
const MAX_BOOTSTRAP_ATTEMPTS = 5
|
|
76
92
|
const IMMEDIATE_RESTART_MAX_THRESHOLD = 10
|
|
@@ -119,6 +135,8 @@ export class Runtime extends EventEmitter {
|
|
|
119
135
|
|
|
120
136
|
#channelCreationHook
|
|
121
137
|
|
|
138
|
+
#processMetricsRegistry
|
|
139
|
+
|
|
122
140
|
constructor (config, context) {
|
|
123
141
|
super()
|
|
124
142
|
this.setMaxListeners(MAX_LISTENERS_COUNT)
|
|
@@ -197,6 +215,14 @@ export class Runtime extends EventEmitter {
|
|
|
197
215
|
this.#metricsLabelName = 'applicationId'
|
|
198
216
|
}
|
|
199
217
|
|
|
218
|
+
// Initialize process-level metrics registry in the main thread if metrics or management API is enabled
|
|
219
|
+
// These metrics are the same across all workers and only need to be collected once
|
|
220
|
+
// We need this for management API as it can request metrics even without explicit metrics config
|
|
221
|
+
if (config.metrics || config.managementApi) {
|
|
222
|
+
this.#processMetricsRegistry = new metricsClient.Registry()
|
|
223
|
+
collectProcessMetrics(this.#processMetricsRegistry)
|
|
224
|
+
}
|
|
225
|
+
|
|
200
226
|
// Create the logger
|
|
201
227
|
const [logger, destination, context] = await createLogger(config)
|
|
202
228
|
this.logger = logger
|
|
@@ -346,6 +372,12 @@ export class Runtime extends EventEmitter {
|
|
|
346
372
|
await this.#prometheusServer.close()
|
|
347
373
|
}
|
|
348
374
|
|
|
375
|
+
// Clean up process metrics registry
|
|
376
|
+
if (this.#processMetricsRegistry) {
|
|
377
|
+
this.#processMetricsRegistry.clear()
|
|
378
|
+
this.#processMetricsRegistry = null
|
|
379
|
+
}
|
|
380
|
+
|
|
349
381
|
if (this.#sharedHttpCache?.close) {
|
|
350
382
|
await this.#sharedHttpCache.close()
|
|
351
383
|
}
|
|
@@ -1059,6 +1091,12 @@ export class Runtime extends EventEmitter {
|
|
|
1059
1091
|
async getMetrics (format = 'json') {
|
|
1060
1092
|
let metrics = null
|
|
1061
1093
|
|
|
1094
|
+
// Get process-level metrics once from main thread registry (if available)
|
|
1095
|
+
let processMetricsJson = null
|
|
1096
|
+
if (this.#processMetricsRegistry) {
|
|
1097
|
+
processMetricsJson = await this.#processMetricsRegistry.getMetricsAsJSON()
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1062
1100
|
for (const worker of this.#workers.values()) {
|
|
1063
1101
|
try {
|
|
1064
1102
|
// The application might be temporarily unavailable
|
|
@@ -1066,6 +1104,7 @@ export class Runtime extends EventEmitter {
|
|
|
1066
1104
|
continue
|
|
1067
1105
|
}
|
|
1068
1106
|
|
|
1107
|
+
// Get thread-specific metrics from worker
|
|
1069
1108
|
const applicationMetrics = await executeWithTimeout(
|
|
1070
1109
|
sendViaITC(worker, 'getMetrics', format),
|
|
1071
1110
|
this.#config.metrics?.timeout ?? 10000
|
|
@@ -1076,9 +1115,30 @@ export class Runtime extends EventEmitter {
|
|
|
1076
1115
|
metrics = format === 'json' ? [] : ''
|
|
1077
1116
|
}
|
|
1078
1117
|
|
|
1118
|
+
// Build worker labels including custom labels from metrics config
|
|
1119
|
+
const workerLabels = {
|
|
1120
|
+
...this.#config.metrics?.labels,
|
|
1121
|
+
[this.#metricsLabelName]: worker[kApplicationId]
|
|
1122
|
+
}
|
|
1123
|
+
const workerId = worker[kWorkerId]
|
|
1124
|
+
if (workerId >= 0) {
|
|
1125
|
+
workerLabels.workerId = workerId
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1079
1128
|
if (format === 'json') {
|
|
1080
|
-
metrics
|
|
1129
|
+
// Duplicate process metrics with worker labels and add to output
|
|
1130
|
+
if (processMetricsJson) {
|
|
1131
|
+
this.#applyLabelsToMetrics(processMetricsJson, workerLabels, metrics)
|
|
1132
|
+
}
|
|
1133
|
+
// Add worker's thread-specific metrics
|
|
1134
|
+
for (let i = 0; i < applicationMetrics.length; i++) {
|
|
1135
|
+
metrics.push(applicationMetrics[i])
|
|
1136
|
+
}
|
|
1081
1137
|
} else {
|
|
1138
|
+
// Text format: format process metrics with worker labels
|
|
1139
|
+
if (processMetricsJson) {
|
|
1140
|
+
metrics += this.#formatProcessMetricsText(processMetricsJson, workerLabels)
|
|
1141
|
+
}
|
|
1082
1142
|
metrics += applicationMetrics
|
|
1083
1143
|
}
|
|
1084
1144
|
}
|
|
@@ -1099,6 +1159,65 @@ export class Runtime extends EventEmitter {
|
|
|
1099
1159
|
return { metrics }
|
|
1100
1160
|
}
|
|
1101
1161
|
|
|
1162
|
+
// Apply labels to process metrics and push to output array (for JSON format)
|
|
1163
|
+
#applyLabelsToMetrics (processMetrics, labels, outputArray) {
|
|
1164
|
+
for (let i = 0; i < processMetrics.length; i++) {
|
|
1165
|
+
const metric = processMetrics[i]
|
|
1166
|
+
const newValues = []
|
|
1167
|
+
const values = metric.values
|
|
1168
|
+
for (let j = 0; j < values.length; j++) {
|
|
1169
|
+
const v = values[j]
|
|
1170
|
+
newValues.push({
|
|
1171
|
+
value: v.value,
|
|
1172
|
+
labels: { ...labels, ...v.labels },
|
|
1173
|
+
metricName: v.metricName
|
|
1174
|
+
})
|
|
1175
|
+
}
|
|
1176
|
+
outputArray.push({
|
|
1177
|
+
name: metric.name,
|
|
1178
|
+
help: metric.help,
|
|
1179
|
+
type: metric.type,
|
|
1180
|
+
aggregator: metric.aggregator,
|
|
1181
|
+
values: newValues
|
|
1182
|
+
})
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
1185
|
+
|
|
1186
|
+
// Format process metrics as Prometheus text format with labels
|
|
1187
|
+
#formatProcessMetricsText (processMetricsJson, labels) {
|
|
1188
|
+
let output = ''
|
|
1189
|
+
|
|
1190
|
+
for (let i = 0; i < processMetricsJson.length; i++) {
|
|
1191
|
+
const metric = processMetricsJson[i]
|
|
1192
|
+
const name = metric.name
|
|
1193
|
+
const help = metric.help
|
|
1194
|
+
const type = metric.type
|
|
1195
|
+
|
|
1196
|
+
// Add HELP and TYPE lines
|
|
1197
|
+
output += `# HELP ${name} ${help}\n`
|
|
1198
|
+
output += `# TYPE ${name} ${type}\n`
|
|
1199
|
+
|
|
1200
|
+
const values = metric.values
|
|
1201
|
+
for (let j = 0; j < values.length; j++) {
|
|
1202
|
+
const v = values[j]
|
|
1203
|
+
const combinedLabels = { ...labels, ...v.labels }
|
|
1204
|
+
const labelParts = []
|
|
1205
|
+
|
|
1206
|
+
for (const [key, val] of Object.entries(combinedLabels)) {
|
|
1207
|
+
// Escape label values for Prometheus format
|
|
1208
|
+
const escapedVal = String(val).replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/\n/g, '\\n')
|
|
1209
|
+
labelParts.push(`${key}="${escapedVal}"`)
|
|
1210
|
+
}
|
|
1211
|
+
|
|
1212
|
+
const labelStr = labelParts.length > 0 ? `{${labelParts.join(',')}}` : ''
|
|
1213
|
+
const metricName = v.metricName || name
|
|
1214
|
+
output += `${metricName}${labelStr} ${v.value}\n`
|
|
1215
|
+
}
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1218
|
+
return output
|
|
1219
|
+
}
|
|
1220
|
+
|
|
1102
1221
|
async getFormattedMetrics () {
|
|
1103
1222
|
try {
|
|
1104
1223
|
const { metrics } = await this.getMetrics()
|
|
@@ -1349,7 +1468,7 @@ export class Runtime extends EventEmitter {
|
|
|
1349
1468
|
elu = worker.performance.eventLoopUtilization(elu, previousELU)
|
|
1350
1469
|
}
|
|
1351
1470
|
|
|
1352
|
-
if (!features.node.worker.getHeapStatistics
|
|
1471
|
+
if (!features.node.worker.getHeapStatistics) {
|
|
1353
1472
|
return { elu: elu.utilization, currentELU }
|
|
1354
1473
|
}
|
|
1355
1474
|
|
|
@@ -1396,7 +1515,10 @@ export class Runtime extends EventEmitter {
|
|
|
1396
1515
|
interceptors.push(
|
|
1397
1516
|
undiciInterceptors.cache({
|
|
1398
1517
|
store: this.#sharedHttpCache,
|
|
1399
|
-
methods: config.httpCache.methods ?? ['GET', 'HEAD']
|
|
1518
|
+
methods: config.httpCache.methods ?? ['GET', 'HEAD'],
|
|
1519
|
+
origins: parseOrigins(config.httpCache.origins),
|
|
1520
|
+
cacheByDefault: config.httpCache.cacheByDefault,
|
|
1521
|
+
type: config.httpCache.type
|
|
1400
1522
|
})
|
|
1401
1523
|
)
|
|
1402
1524
|
}
|
|
@@ -1564,7 +1686,8 @@ export class Runtime extends EventEmitter {
|
|
|
1564
1686
|
codeRangeSizeMb
|
|
1565
1687
|
},
|
|
1566
1688
|
stdout: true,
|
|
1567
|
-
stderr: true
|
|
1689
|
+
stderr: true,
|
|
1690
|
+
name: workerId
|
|
1568
1691
|
})
|
|
1569
1692
|
|
|
1570
1693
|
this.#handleWorkerStandardStreams(worker, applicationId, index)
|
|
@@ -1753,8 +1876,7 @@ export class Runtime extends EventEmitter {
|
|
|
1753
1876
|
let health = null
|
|
1754
1877
|
try {
|
|
1755
1878
|
health = await this.getWorkerHealth(worker, {
|
|
1756
|
-
previousELU: worker[kLastHealthCheckELU]
|
|
1757
|
-
noHeapCheck: worker[kConfig]?.health?.noHeapCheck
|
|
1879
|
+
previousELU: worker[kLastHealthCheckELU]
|
|
1758
1880
|
})
|
|
1759
1881
|
} catch (err) {
|
|
1760
1882
|
this.logger.error({ err }, `Failed to get health for ${errorLabel}.`)
|
|
@@ -1798,7 +1920,7 @@ export class Runtime extends EventEmitter {
|
|
|
1798
1920
|
|
|
1799
1921
|
const healthConfig = worker[kConfig].health
|
|
1800
1922
|
|
|
1801
|
-
let { maxELU, maxHeapUsed, maxHeapTotal, maxUnhealthyChecks, interval
|
|
1923
|
+
let { maxELU, maxHeapUsed, maxHeapTotal, maxUnhealthyChecks, interval } = worker[kConfig].health
|
|
1802
1924
|
|
|
1803
1925
|
if (typeof maxHeapTotal === 'string') {
|
|
1804
1926
|
maxHeapTotal = parseMemorySize(maxHeapTotal)
|
|
@@ -1829,8 +1951,8 @@ export class Runtime extends EventEmitter {
|
|
|
1829
1951
|
|
|
1830
1952
|
if (lastHealthMetrics) {
|
|
1831
1953
|
const health = lastHealthMetrics.currentHealth
|
|
1832
|
-
const memoryUsage =
|
|
1833
|
-
const unhealthy = health.elu > maxELU ||
|
|
1954
|
+
const memoryUsage = health.heapUsed / maxHeapTotal
|
|
1955
|
+
const unhealthy = health.elu > maxELU || memoryUsage > maxHeapUsed
|
|
1834
1956
|
|
|
1835
1957
|
this.emit('application:worker:health', {
|
|
1836
1958
|
id: worker[kId],
|
|
@@ -1848,7 +1970,7 @@ export class Runtime extends EventEmitter {
|
|
|
1848
1970
|
)
|
|
1849
1971
|
}
|
|
1850
1972
|
|
|
1851
|
-
if (
|
|
1973
|
+
if (memoryUsage > maxHeapUsed) {
|
|
1852
1974
|
this.logger.error(
|
|
1853
1975
|
`The ${errorLabel} is using ${(memoryUsage * 100).toFixed(2)} % of the memory, ` +
|
|
1854
1976
|
`above the maximum allowed usage of ${(maxHeapUsed * 100).toFixed(2)} %.`
|
|
@@ -178,7 +178,23 @@ function createThreadInterceptor (runtimeConfig) {
|
|
|
178
178
|
return threadDispatcher
|
|
179
179
|
}
|
|
180
180
|
|
|
181
|
+
function parseOrigins (origins) {
|
|
182
|
+
if (!origins) return undefined
|
|
183
|
+
|
|
184
|
+
return origins.map(origin => {
|
|
185
|
+
// Check if the origin is a regex pattern (starts and ends with /)
|
|
186
|
+
if (origin.startsWith('/') && origin.lastIndexOf('/') > 0) {
|
|
187
|
+
const lastSlash = origin.lastIndexOf('/')
|
|
188
|
+
const pattern = origin.slice(1, lastSlash)
|
|
189
|
+
const flags = origin.slice(lastSlash + 1)
|
|
190
|
+
return new RegExp(pattern, flags)
|
|
191
|
+
}
|
|
192
|
+
return origin
|
|
193
|
+
})
|
|
194
|
+
}
|
|
195
|
+
|
|
181
196
|
function createHttpCacheInterceptor (runtimeConfig) {
|
|
197
|
+
const httpCache = runtimeConfig.httpCache
|
|
182
198
|
const cacheInterceptor = httpCacheInterceptor({
|
|
183
199
|
store: new RemoteCacheStore({
|
|
184
200
|
onRequest: opts => {
|
|
@@ -192,7 +208,10 @@ function createHttpCacheInterceptor (runtimeConfig) {
|
|
|
192
208
|
},
|
|
193
209
|
logger: globalThis.platformatic.logger
|
|
194
210
|
}),
|
|
195
|
-
methods:
|
|
211
|
+
methods: httpCache.methods ?? ['GET', 'HEAD'],
|
|
212
|
+
origins: parseOrigins(httpCache.origins),
|
|
213
|
+
cacheByDefault: httpCache.cacheByDefault,
|
|
214
|
+
type: httpCache.type,
|
|
196
215
|
logger: globalThis.platformatic.logger
|
|
197
216
|
})
|
|
198
217
|
return cacheInterceptor
|
package/lib/worker/main.js
CHANGED
|
@@ -9,7 +9,7 @@ import { EventEmitter } from 'node:events'
|
|
|
9
9
|
import { ServerResponse } from 'node:http'
|
|
10
10
|
import inspector from 'node:inspector'
|
|
11
11
|
import { hostname } from 'node:os'
|
|
12
|
-
import { resolve } from 'node:path'
|
|
12
|
+
import { join, resolve } from 'node:path'
|
|
13
13
|
import { pathToFileURL } from 'node:url'
|
|
14
14
|
import { threadId, workerData } from 'node:worker_threads'
|
|
15
15
|
import pino from 'pino'
|
|
@@ -85,6 +85,57 @@ async function performPreloading (...sources) {
|
|
|
85
85
|
}
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
+
// Enable compile cache if configured (Node.js 22.1.0+)
|
|
89
|
+
async function setupCompileCache (runtimeConfig, applicationConfig, logger) {
|
|
90
|
+
// Normalize boolean shorthand: true -> { enabled: true }
|
|
91
|
+
const normalizeConfig = cfg => {
|
|
92
|
+
if (cfg === true) return { enabled: true }
|
|
93
|
+
if (cfg === false) return { enabled: false }
|
|
94
|
+
return cfg
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Merge runtime and app-level config (app overrides runtime)
|
|
98
|
+
const runtimeCache = normalizeConfig(runtimeConfig.compileCache)
|
|
99
|
+
const appCache = normalizeConfig(applicationConfig.compileCache)
|
|
100
|
+
const config = { ...runtimeCache, ...appCache }
|
|
101
|
+
|
|
102
|
+
if (!config.enabled) {
|
|
103
|
+
return
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Check if API is available (Node.js 22.1.0+)
|
|
107
|
+
let moduleApi
|
|
108
|
+
try {
|
|
109
|
+
moduleApi = await import('node:module')
|
|
110
|
+
if (typeof moduleApi.enableCompileCache !== 'function') {
|
|
111
|
+
return
|
|
112
|
+
}
|
|
113
|
+
} catch {
|
|
114
|
+
return
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Determine cache directory - use applicationConfig.path for the app root
|
|
118
|
+
const cacheDir = config.directory ?? join(applicationConfig.path, '.plt', 'compile-cache')
|
|
119
|
+
|
|
120
|
+
try {
|
|
121
|
+
const result = moduleApi.enableCompileCache(cacheDir)
|
|
122
|
+
|
|
123
|
+
const { compileCacheStatus } = moduleApi.constants ?? {}
|
|
124
|
+
|
|
125
|
+
if (result.status === compileCacheStatus?.ENABLED) {
|
|
126
|
+
logger.debug({ directory: result.directory }, 'Module compile cache enabled')
|
|
127
|
+
} else if (result.status === compileCacheStatus?.ALREADY_ENABLED) {
|
|
128
|
+
logger.debug({ directory: result.directory }, 'Module compile cache already enabled')
|
|
129
|
+
} else if (result.status === compileCacheStatus?.FAILED) {
|
|
130
|
+
logger.warn({ message: result.message }, 'Failed to enable module compile cache')
|
|
131
|
+
} else if (result.status === compileCacheStatus?.DISABLED) {
|
|
132
|
+
logger.debug('Module compile cache disabled via NODE_DISABLE_COMPILE_CACHE')
|
|
133
|
+
}
|
|
134
|
+
} catch (err) {
|
|
135
|
+
logger.warn({ err }, 'Error enabling module compile cache')
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
88
139
|
async function main () {
|
|
89
140
|
globalThis.fetch = fetch
|
|
90
141
|
globalThis[kId] = threadId
|
|
@@ -94,10 +145,12 @@ async function main () {
|
|
|
94
145
|
})
|
|
95
146
|
|
|
96
147
|
const runtimeConfig = workerData.config
|
|
148
|
+
const applicationConfig = workerData.applicationConfig
|
|
97
149
|
|
|
98
|
-
|
|
150
|
+
// Enable compile cache early before loading user modules
|
|
151
|
+
await setupCompileCache(runtimeConfig, applicationConfig, globalThis.platformatic.logger)
|
|
99
152
|
|
|
100
|
-
|
|
153
|
+
await performPreloading(runtimeConfig, applicationConfig)
|
|
101
154
|
|
|
102
155
|
// Load env file and mixin env vars from application config
|
|
103
156
|
let envfile
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@platformatic/runtime",
|
|
3
|
-
"version": "3.32.0-alpha.
|
|
3
|
+
"version": "3.32.0-alpha.1",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -35,14 +35,14 @@
|
|
|
35
35
|
"typescript": "^5.5.4",
|
|
36
36
|
"undici-oidc-interceptor": "^0.5.0",
|
|
37
37
|
"why-is-node-running": "^2.2.2",
|
|
38
|
-
"@platformatic/composer": "3.32.0-alpha.
|
|
39
|
-
"@platformatic/db": "3.32.0-alpha.
|
|
40
|
-
"@platformatic/
|
|
41
|
-
"@platformatic/
|
|
42
|
-
"@platformatic/
|
|
43
|
-
"@platformatic/sql-graphql": "3.32.0-alpha.
|
|
44
|
-
"@platformatic/
|
|
45
|
-
"@platformatic/
|
|
38
|
+
"@platformatic/composer": "3.32.0-alpha.1",
|
|
39
|
+
"@platformatic/db": "3.32.0-alpha.1",
|
|
40
|
+
"@platformatic/gateway": "3.32.0-alpha.1",
|
|
41
|
+
"@platformatic/node": "3.32.0-alpha.1",
|
|
42
|
+
"@platformatic/service": "3.32.0-alpha.1",
|
|
43
|
+
"@platformatic/sql-graphql": "3.32.0-alpha.1",
|
|
44
|
+
"@platformatic/sql-mapper": "3.32.0-alpha.1",
|
|
45
|
+
"@platformatic/wattpm-pprof-capture": "3.32.0-alpha.1"
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
48
|
"@fastify/accepts": "^5.0.0",
|
|
@@ -71,12 +71,12 @@
|
|
|
71
71
|
"undici": "^7.0.0",
|
|
72
72
|
"undici-thread-interceptor": "^1.0.0",
|
|
73
73
|
"ws": "^8.16.0",
|
|
74
|
-
"@platformatic/basic": "3.32.0-alpha.
|
|
75
|
-
"@platformatic/foundation": "3.32.0-alpha.
|
|
76
|
-
"@platformatic/generators": "3.32.0-alpha.
|
|
77
|
-
"@platformatic/itc": "3.32.0-alpha.
|
|
78
|
-
"@platformatic/metrics": "3.32.0-alpha.
|
|
79
|
-
"@platformatic/telemetry": "3.32.0-alpha.
|
|
74
|
+
"@platformatic/basic": "3.32.0-alpha.1",
|
|
75
|
+
"@platformatic/foundation": "3.32.0-alpha.1",
|
|
76
|
+
"@platformatic/generators": "3.32.0-alpha.1",
|
|
77
|
+
"@platformatic/itc": "3.32.0-alpha.1",
|
|
78
|
+
"@platformatic/metrics": "3.32.0-alpha.1",
|
|
79
|
+
"@platformatic/telemetry": "3.32.0-alpha.1"
|
|
80
80
|
},
|
|
81
81
|
"engines": {
|
|
82
82
|
"node": ">=22.19.0"
|
package/schema.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"$id": "https://schemas.platformatic.dev/@platformatic/runtime/3.32.0-alpha.
|
|
2
|
+
"$id": "https://schemas.platformatic.dev/@platformatic/runtime/3.32.0-alpha.1.json",
|
|
3
3
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
4
4
|
"title": "Platformatic Runtime Config",
|
|
5
5
|
"type": "object",
|
|
@@ -208,16 +208,6 @@
|
|
|
208
208
|
"type": "string"
|
|
209
209
|
}
|
|
210
210
|
]
|
|
211
|
-
},
|
|
212
|
-
"noHeapCheck": {
|
|
213
|
-
"anyOf": [
|
|
214
|
-
{
|
|
215
|
-
"type": "boolean"
|
|
216
|
-
},
|
|
217
|
-
{
|
|
218
|
-
"type": "string"
|
|
219
|
-
}
|
|
220
|
-
]
|
|
221
211
|
}
|
|
222
212
|
},
|
|
223
213
|
"additionalProperties": false
|
|
@@ -342,6 +332,28 @@
|
|
|
342
332
|
}
|
|
343
333
|
}
|
|
344
334
|
}
|
|
335
|
+
},
|
|
336
|
+
"compileCache": {
|
|
337
|
+
"anyOf": [
|
|
338
|
+
{
|
|
339
|
+
"type": "boolean"
|
|
340
|
+
},
|
|
341
|
+
{
|
|
342
|
+
"type": "object",
|
|
343
|
+
"properties": {
|
|
344
|
+
"enabled": {
|
|
345
|
+
"type": "boolean",
|
|
346
|
+
"default": true,
|
|
347
|
+
"description": "Enable Node.js module compile cache for faster startup"
|
|
348
|
+
},
|
|
349
|
+
"directory": {
|
|
350
|
+
"type": "string",
|
|
351
|
+
"description": "Directory to store compile cache. Defaults to .plt/compile-cache in app root"
|
|
352
|
+
}
|
|
353
|
+
},
|
|
354
|
+
"additionalProperties": false
|
|
355
|
+
}
|
|
356
|
+
]
|
|
345
357
|
}
|
|
346
358
|
}
|
|
347
359
|
}
|
|
@@ -532,16 +544,6 @@
|
|
|
532
544
|
"type": "string"
|
|
533
545
|
}
|
|
534
546
|
]
|
|
535
|
-
},
|
|
536
|
-
"noHeapCheck": {
|
|
537
|
-
"anyOf": [
|
|
538
|
-
{
|
|
539
|
-
"type": "boolean"
|
|
540
|
-
},
|
|
541
|
-
{
|
|
542
|
-
"type": "string"
|
|
543
|
-
}
|
|
544
|
-
]
|
|
545
547
|
}
|
|
546
548
|
},
|
|
547
549
|
"additionalProperties": false
|
|
@@ -666,6 +668,28 @@
|
|
|
666
668
|
}
|
|
667
669
|
}
|
|
668
670
|
}
|
|
671
|
+
},
|
|
672
|
+
"compileCache": {
|
|
673
|
+
"anyOf": [
|
|
674
|
+
{
|
|
675
|
+
"type": "boolean"
|
|
676
|
+
},
|
|
677
|
+
{
|
|
678
|
+
"type": "object",
|
|
679
|
+
"properties": {
|
|
680
|
+
"enabled": {
|
|
681
|
+
"type": "boolean",
|
|
682
|
+
"default": true,
|
|
683
|
+
"description": "Enable Node.js module compile cache for faster startup"
|
|
684
|
+
},
|
|
685
|
+
"directory": {
|
|
686
|
+
"type": "string",
|
|
687
|
+
"description": "Directory to store compile cache. Defaults to .plt/compile-cache in app root"
|
|
688
|
+
}
|
|
689
|
+
},
|
|
690
|
+
"additionalProperties": false
|
|
691
|
+
}
|
|
692
|
+
]
|
|
669
693
|
}
|
|
670
694
|
}
|
|
671
695
|
}
|
|
@@ -854,16 +878,6 @@
|
|
|
854
878
|
"type": "string"
|
|
855
879
|
}
|
|
856
880
|
]
|
|
857
|
-
},
|
|
858
|
-
"noHeapCheck": {
|
|
859
|
-
"anyOf": [
|
|
860
|
-
{
|
|
861
|
-
"type": "boolean"
|
|
862
|
-
},
|
|
863
|
-
{
|
|
864
|
-
"type": "string"
|
|
865
|
-
}
|
|
866
|
-
]
|
|
867
881
|
}
|
|
868
882
|
},
|
|
869
883
|
"additionalProperties": false
|
|
@@ -988,6 +1002,28 @@
|
|
|
988
1002
|
}
|
|
989
1003
|
}
|
|
990
1004
|
}
|
|
1005
|
+
},
|
|
1006
|
+
"compileCache": {
|
|
1007
|
+
"anyOf": [
|
|
1008
|
+
{
|
|
1009
|
+
"type": "boolean"
|
|
1010
|
+
},
|
|
1011
|
+
{
|
|
1012
|
+
"type": "object",
|
|
1013
|
+
"properties": {
|
|
1014
|
+
"enabled": {
|
|
1015
|
+
"type": "boolean",
|
|
1016
|
+
"default": true,
|
|
1017
|
+
"description": "Enable Node.js module compile cache for faster startup"
|
|
1018
|
+
},
|
|
1019
|
+
"directory": {
|
|
1020
|
+
"type": "string",
|
|
1021
|
+
"description": "Directory to store compile cache. Defaults to .plt/compile-cache in app root"
|
|
1022
|
+
}
|
|
1023
|
+
},
|
|
1024
|
+
"additionalProperties": false
|
|
1025
|
+
}
|
|
1026
|
+
]
|
|
991
1027
|
}
|
|
992
1028
|
}
|
|
993
1029
|
}
|
|
@@ -1176,16 +1212,6 @@
|
|
|
1176
1212
|
"type": "string"
|
|
1177
1213
|
}
|
|
1178
1214
|
]
|
|
1179
|
-
},
|
|
1180
|
-
"noHeapCheck": {
|
|
1181
|
-
"anyOf": [
|
|
1182
|
-
{
|
|
1183
|
-
"type": "boolean"
|
|
1184
|
-
},
|
|
1185
|
-
{
|
|
1186
|
-
"type": "string"
|
|
1187
|
-
}
|
|
1188
|
-
]
|
|
1189
1215
|
}
|
|
1190
1216
|
},
|
|
1191
1217
|
"additionalProperties": false
|
|
@@ -1310,6 +1336,28 @@
|
|
|
1310
1336
|
}
|
|
1311
1337
|
}
|
|
1312
1338
|
}
|
|
1339
|
+
},
|
|
1340
|
+
"compileCache": {
|
|
1341
|
+
"anyOf": [
|
|
1342
|
+
{
|
|
1343
|
+
"type": "boolean"
|
|
1344
|
+
},
|
|
1345
|
+
{
|
|
1346
|
+
"type": "object",
|
|
1347
|
+
"properties": {
|
|
1348
|
+
"enabled": {
|
|
1349
|
+
"type": "boolean",
|
|
1350
|
+
"default": true,
|
|
1351
|
+
"description": "Enable Node.js module compile cache for faster startup"
|
|
1352
|
+
},
|
|
1353
|
+
"directory": {
|
|
1354
|
+
"type": "string",
|
|
1355
|
+
"description": "Directory to store compile cache. Defaults to .plt/compile-cache in app root"
|
|
1356
|
+
}
|
|
1357
|
+
},
|
|
1358
|
+
"additionalProperties": false
|
|
1359
|
+
}
|
|
1360
|
+
]
|
|
1313
1361
|
}
|
|
1314
1362
|
}
|
|
1315
1363
|
}
|
|
@@ -1389,7 +1437,6 @@
|
|
|
1389
1437
|
"properties": {
|
|
1390
1438
|
"level": {
|
|
1391
1439
|
"type": "string",
|
|
1392
|
-
"default": "info",
|
|
1393
1440
|
"oneOf": [
|
|
1394
1441
|
{
|
|
1395
1442
|
"enum": [
|
|
@@ -1536,9 +1583,6 @@
|
|
|
1536
1583
|
"default": true
|
|
1537
1584
|
}
|
|
1538
1585
|
},
|
|
1539
|
-
"required": [
|
|
1540
|
-
"level"
|
|
1541
|
-
],
|
|
1542
1586
|
"default": {},
|
|
1543
1587
|
"additionalProperties": true
|
|
1544
1588
|
},
|
|
@@ -1834,17 +1878,6 @@
|
|
|
1834
1878
|
}
|
|
1835
1879
|
],
|
|
1836
1880
|
"default": 268435456
|
|
1837
|
-
},
|
|
1838
|
-
"noHeapCheck": {
|
|
1839
|
-
"anyOf": [
|
|
1840
|
-
{
|
|
1841
|
-
"type": "boolean"
|
|
1842
|
-
},
|
|
1843
|
-
{
|
|
1844
|
-
"type": "string"
|
|
1845
|
-
}
|
|
1846
|
-
],
|
|
1847
|
-
"default": false
|
|
1848
1881
|
}
|
|
1849
1882
|
},
|
|
1850
1883
|
"additionalProperties": false
|
|
@@ -1976,6 +2009,26 @@
|
|
|
1976
2009
|
},
|
|
1977
2010
|
"maxCount": {
|
|
1978
2011
|
"type": "integer"
|
|
2012
|
+
},
|
|
2013
|
+
"origins": {
|
|
2014
|
+
"type": "array",
|
|
2015
|
+
"items": {
|
|
2016
|
+
"type": "string"
|
|
2017
|
+
},
|
|
2018
|
+
"description": "Whitelist of origins to cache. Supports exact strings and regex patterns (e.g., \"/https:\\\\/\\\\/.*\\\\.example\\\\.com/\")."
|
|
2019
|
+
},
|
|
2020
|
+
"cacheByDefault": {
|
|
2021
|
+
"type": "integer",
|
|
2022
|
+
"description": "Default cache duration in seconds for responses without explicit expiration headers."
|
|
2023
|
+
},
|
|
2024
|
+
"type": {
|
|
2025
|
+
"type": "string",
|
|
2026
|
+
"enum": [
|
|
2027
|
+
"shared",
|
|
2028
|
+
"private"
|
|
2029
|
+
],
|
|
2030
|
+
"default": "shared",
|
|
2031
|
+
"description": "Cache type. \"shared\" caches may be shared between users, \"private\" caches are user-specific."
|
|
1979
2032
|
}
|
|
1980
2033
|
}
|
|
1981
2034
|
}
|
|
@@ -2621,6 +2674,28 @@
|
|
|
2621
2674
|
"deny"
|
|
2622
2675
|
],
|
|
2623
2676
|
"additionalProperties": false
|
|
2677
|
+
},
|
|
2678
|
+
"compileCache": {
|
|
2679
|
+
"anyOf": [
|
|
2680
|
+
{
|
|
2681
|
+
"type": "boolean"
|
|
2682
|
+
},
|
|
2683
|
+
{
|
|
2684
|
+
"type": "object",
|
|
2685
|
+
"properties": {
|
|
2686
|
+
"enabled": {
|
|
2687
|
+
"type": "boolean",
|
|
2688
|
+
"default": true,
|
|
2689
|
+
"description": "Enable Node.js module compile cache for faster startup"
|
|
2690
|
+
},
|
|
2691
|
+
"directory": {
|
|
2692
|
+
"type": "string",
|
|
2693
|
+
"description": "Directory to store compile cache. Defaults to .plt/compile-cache in app root"
|
|
2694
|
+
}
|
|
2695
|
+
},
|
|
2696
|
+
"additionalProperties": false
|
|
2697
|
+
}
|
|
2698
|
+
]
|
|
2624
2699
|
}
|
|
2625
2700
|
},
|
|
2626
2701
|
"anyOf": [
|