@platformatic/runtime 3.59.0 → 3.61.0
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 +61 -1
- package/index.js +2 -2
- package/lib/errors.js +1 -1
- package/lib/management-api.js +10 -1
- package/lib/opentelemetry-metrics.js +93 -0
- package/lib/prom-server.js +65 -3
- package/lib/runtime.js +56 -6
- package/package.json +18 -16
- package/schema.json +157 -2
package/config.d.ts
CHANGED
|
@@ -254,7 +254,40 @@ export type PlatformaticRuntimeConfig = {
|
|
|
254
254
|
bufferPoolSize?: number | string;
|
|
255
255
|
defaultHighWaterMark?: number | string;
|
|
256
256
|
};
|
|
257
|
-
healthProbes?:
|
|
257
|
+
healthProbes?:
|
|
258
|
+
| boolean
|
|
259
|
+
| string
|
|
260
|
+
| {
|
|
261
|
+
enabled?: boolean | string;
|
|
262
|
+
hostname?: string;
|
|
263
|
+
port?: number | string;
|
|
264
|
+
readiness?:
|
|
265
|
+
| boolean
|
|
266
|
+
| {
|
|
267
|
+
endpoint?: string;
|
|
268
|
+
success?: {
|
|
269
|
+
statusCode?: number;
|
|
270
|
+
body?: string;
|
|
271
|
+
};
|
|
272
|
+
fail?: {
|
|
273
|
+
statusCode?: number;
|
|
274
|
+
body?: string;
|
|
275
|
+
};
|
|
276
|
+
};
|
|
277
|
+
liveness?:
|
|
278
|
+
| boolean
|
|
279
|
+
| {
|
|
280
|
+
endpoint?: string;
|
|
281
|
+
success?: {
|
|
282
|
+
statusCode?: number;
|
|
283
|
+
body?: string;
|
|
284
|
+
};
|
|
285
|
+
fail?: {
|
|
286
|
+
statusCode?: number;
|
|
287
|
+
body?: string;
|
|
288
|
+
};
|
|
289
|
+
};
|
|
290
|
+
};
|
|
258
291
|
undici?: {
|
|
259
292
|
agentOptions?: {
|
|
260
293
|
[k: string]: unknown;
|
|
@@ -413,6 +446,10 @@ export type PlatformaticRuntimeConfig = {
|
|
|
413
446
|
body?: string;
|
|
414
447
|
};
|
|
415
448
|
};
|
|
449
|
+
/**
|
|
450
|
+
* @deprecated
|
|
451
|
+
* Deprecated. Health probe timeout configuration is no longer used.
|
|
452
|
+
*/
|
|
416
453
|
healthChecksTimeouts?: number | string;
|
|
417
454
|
plugins?: string[];
|
|
418
455
|
timeout?: number | string;
|
|
@@ -447,6 +484,29 @@ export type PlatformaticRuntimeConfig = {
|
|
|
447
484
|
*/
|
|
448
485
|
serviceVersion?: string;
|
|
449
486
|
};
|
|
487
|
+
/**
|
|
488
|
+
* Configuration for forwarding user OpenTelemetry metrics to an OTLP endpoint
|
|
489
|
+
*/
|
|
490
|
+
opentelemetry?: {
|
|
491
|
+
/**
|
|
492
|
+
* Enable or disable OpenTelemetry metrics forwarding
|
|
493
|
+
*/
|
|
494
|
+
enabled?: boolean | string;
|
|
495
|
+
/**
|
|
496
|
+
* OTLP metrics endpoint URL (e.g., http://collector:4318/v1/metrics)
|
|
497
|
+
*/
|
|
498
|
+
endpoint: string;
|
|
499
|
+
/**
|
|
500
|
+
* Interval in milliseconds between metric forwards
|
|
501
|
+
*/
|
|
502
|
+
interval?: number | string;
|
|
503
|
+
/**
|
|
504
|
+
* Additional HTTP headers for authentication
|
|
505
|
+
*/
|
|
506
|
+
headers?: {
|
|
507
|
+
[k: string]: string;
|
|
508
|
+
};
|
|
509
|
+
};
|
|
450
510
|
/**
|
|
451
511
|
* Custom labels to add to HTTP metrics (http_request_all_duration_seconds). Each label extracts its value from an HTTP request header.
|
|
452
512
|
*/
|
package/index.js
CHANGED
|
@@ -87,7 +87,7 @@ export async function loadConfiguration (configOrRoot, sourceOrConfig, context)
|
|
|
87
87
|
})
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
-
export async function loadApplicationsCommands (executableName = '') {
|
|
90
|
+
export async function loadApplicationsCommands (executableName = '', configurationFile = null) {
|
|
91
91
|
const applications = {}
|
|
92
92
|
const commands = {}
|
|
93
93
|
const help = {}
|
|
@@ -97,7 +97,7 @@ export async function loadApplicationsCommands (executableName = '') {
|
|
|
97
97
|
const file = await findRuntimeConfigurationFile(
|
|
98
98
|
abstractLogger,
|
|
99
99
|
process.cwd(),
|
|
100
|
-
|
|
100
|
+
configurationFile,
|
|
101
101
|
false,
|
|
102
102
|
false,
|
|
103
103
|
true,
|
package/lib/errors.js
CHANGED
|
@@ -39,7 +39,7 @@ export const ApplicationNotFoundError = createError(
|
|
|
39
39
|
)
|
|
40
40
|
export const WorkerNotFoundError = createError(
|
|
41
41
|
`${ERROR_PREFIX}_WORKER_NOT_FOUND`,
|
|
42
|
-
'Worker %s of application %s not found. Available
|
|
42
|
+
'Worker %s of application %s not found. Available workers are: %s'
|
|
43
43
|
)
|
|
44
44
|
export const ApplicationNotStartedError = createError(
|
|
45
45
|
`${ERROR_PREFIX}_APPLICATION_NOT_STARTED`,
|
package/lib/management-api.js
CHANGED
|
@@ -3,11 +3,13 @@ import fastifyWebsocket from '@fastify/websocket'
|
|
|
3
3
|
import {
|
|
4
4
|
applications as applicationSchema,
|
|
5
5
|
createDirectory,
|
|
6
|
+
createSharedTemporaryDirectory,
|
|
6
7
|
kMetadata,
|
|
7
8
|
safeRemove,
|
|
8
9
|
validate
|
|
9
10
|
} from '@platformatic/foundation'
|
|
10
11
|
import fastify from 'fastify'
|
|
12
|
+
import { chmod } from 'node:fs/promises'
|
|
11
13
|
import { platform, tmpdir } from 'node:os'
|
|
12
14
|
import { dirname, join } from 'node:path'
|
|
13
15
|
import { setTimeout as sleep } from 'node:timers/promises'
|
|
@@ -343,7 +345,14 @@ export async function startManagementApi (runtime, config) {
|
|
|
343
345
|
|
|
344
346
|
const runtimePIDDir = join(PLATFORMATIC_TMP_DIR, runtimePID.toString())
|
|
345
347
|
if (platform() !== 'win32') {
|
|
346
|
-
|
|
348
|
+
if (customSocket) {
|
|
349
|
+
await createDirectory(dirname(customSocket))
|
|
350
|
+
} else {
|
|
351
|
+
await createSharedTemporaryDirectory('platformatic', 'runtimes')
|
|
352
|
+
await createDirectory(runtimePIDDir, true)
|
|
353
|
+
// The socket must only be accessible by the current user
|
|
354
|
+
await chmod(runtimePIDDir, 0o700)
|
|
355
|
+
}
|
|
347
356
|
}
|
|
348
357
|
|
|
349
358
|
let socketPath = null
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
export class OpenTelemetryMetricsForwarder {
|
|
2
|
+
#config
|
|
3
|
+
#exporter
|
|
4
|
+
#logger
|
|
5
|
+
#queue
|
|
6
|
+
#timer
|
|
7
|
+
#flushing
|
|
8
|
+
|
|
9
|
+
constructor (config, logger) {
|
|
10
|
+
this.#config = config
|
|
11
|
+
this.#logger = logger
|
|
12
|
+
this.#queue = []
|
|
13
|
+
this.#timer = null
|
|
14
|
+
this.#flushing = false
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async start () {
|
|
18
|
+
if (!this.#config || this.#config.enabled === false || this.#config.enabled === 'false' || !this.#config.endpoint) {
|
|
19
|
+
return false
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const { OTLPMetricExporter } = await import('@opentelemetry/exporter-metrics-otlp-proto')
|
|
23
|
+
this.#exporter = new OTLPMetricExporter({
|
|
24
|
+
url: this.#config.endpoint,
|
|
25
|
+
headers: this.#config.headers
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
const interval = this.#config.interval ?? 60000
|
|
29
|
+
this.#timer = setInterval(() => {
|
|
30
|
+
this.flush().catch(error => {
|
|
31
|
+
this.#logger.error({ err: error }, 'OpenTelemetry metrics export failed.')
|
|
32
|
+
})
|
|
33
|
+
}, interval)
|
|
34
|
+
this.#timer.unref()
|
|
35
|
+
|
|
36
|
+
return true
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
collect (resourceMetrics) {
|
|
40
|
+
if (!this.#exporter) {
|
|
41
|
+
return
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
this.#queue.push(resourceMetrics)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async flush () {
|
|
48
|
+
if (!this.#exporter || this.#flushing || this.#queue.length === 0) {
|
|
49
|
+
return
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
this.#flushing = true
|
|
53
|
+
const batch = this.#queue.splice(0)
|
|
54
|
+
|
|
55
|
+
try {
|
|
56
|
+
await Promise.all(batch.map(resourceMetrics => this.#export(resourceMetrics)))
|
|
57
|
+
} finally {
|
|
58
|
+
this.#flushing = false
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async close () {
|
|
63
|
+
if (this.#timer) {
|
|
64
|
+
clearInterval(this.#timer)
|
|
65
|
+
this.#timer = null
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
try {
|
|
69
|
+
await this.flush()
|
|
70
|
+
} catch (error) {
|
|
71
|
+
this.#logger.error({ err: error }, 'OpenTelemetry metrics export failed.')
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (this.#exporter) {
|
|
75
|
+
await this.#exporter.shutdown()
|
|
76
|
+
this.#exporter = null
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
#export (resourceMetrics) {
|
|
81
|
+
const { promise, resolve, reject } = Promise.withResolvers()
|
|
82
|
+
|
|
83
|
+
this.#exporter.export(resourceMetrics, result => {
|
|
84
|
+
if (result.code === 0) {
|
|
85
|
+
resolve()
|
|
86
|
+
} else {
|
|
87
|
+
reject(result.error ?? new Error('OpenTelemetry metrics export failed.'))
|
|
88
|
+
}
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
return promise
|
|
92
|
+
}
|
|
93
|
+
}
|
package/lib/prom-server.js
CHANGED
|
@@ -76,13 +76,59 @@ async function checkLiveness (runtime) {
|
|
|
76
76
|
return { response, status }
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
79
|
+
function isHealthProbesServerEnabled (healthProbes) {
|
|
80
|
+
return typeof healthProbes === 'object' && healthProbes !== null
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function isHealthProbesEnabled (healthProbes) {
|
|
84
|
+
return healthProbes !== false && healthProbes?.enabled !== false
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function resolveServerAddress (opts, fallback) {
|
|
88
|
+
opts = typeof opts === 'object' && opts !== null ? opts : {}
|
|
89
|
+
fallback = typeof fallback === 'object' && fallback !== null ? fallback : {}
|
|
90
|
+
|
|
91
|
+
return {
|
|
92
|
+
host: opts.hostname ?? fallback.hostname ?? DEFAULT_HOSTNAME,
|
|
93
|
+
port: opts.port ?? fallback.port ?? DEFAULT_PORT
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function useSharedServer (metricsOpts, healthProbes) {
|
|
98
|
+
if (!isHealthProbesServerEnabled(healthProbes)) {
|
|
99
|
+
return true
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const metricsAddress = resolveServerAddress(metricsOpts)
|
|
103
|
+
const healthProbesAddress = resolveServerAddress(healthProbes, metricsOpts)
|
|
104
|
+
|
|
105
|
+
return metricsAddress.host === healthProbesAddress.host && String(metricsAddress.port) === String(healthProbesAddress.port)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function resolveHealthProbesOptions (metricsOpts, healthProbes) {
|
|
109
|
+
metricsOpts = typeof metricsOpts === 'object' && metricsOpts !== null ? metricsOpts : {}
|
|
110
|
+
|
|
111
|
+
if (!isHealthProbesServerEnabled(healthProbes)) {
|
|
112
|
+
return metricsOpts
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const { host, port } = resolveServerAddress(healthProbes, metricsOpts)
|
|
116
|
+
return {
|
|
117
|
+
...healthProbes,
|
|
118
|
+
hostname: host,
|
|
119
|
+
port,
|
|
120
|
+
readiness: healthProbes.readiness ?? metricsOpts.readiness,
|
|
121
|
+
liveness: healthProbes.liveness ?? metricsOpts.liveness
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
async function startServer (runtime, opts, metricsEnabled, healthProbesEnabled) {
|
|
126
|
+
opts = typeof opts === 'object' && opts !== null ? opts : {}
|
|
82
127
|
|
|
83
128
|
if (!metricsEnabled && !healthProbesEnabled) {
|
|
84
129
|
return
|
|
85
130
|
}
|
|
131
|
+
|
|
86
132
|
const host = opts.hostname ?? DEFAULT_HOSTNAME
|
|
87
133
|
const port = opts.port ?? DEFAULT_PORT
|
|
88
134
|
const metricsEndpoint = opts.endpoint ?? DEFAULT_METRICS_ENDPOINT
|
|
@@ -238,3 +284,19 @@ export async function startPrometheusServer (runtime, opts, healthProbes) {
|
|
|
238
284
|
await promServer.listen({ port, host })
|
|
239
285
|
return promServer
|
|
240
286
|
}
|
|
287
|
+
|
|
288
|
+
export async function startPrometheusServer (runtime, opts, healthProbes) {
|
|
289
|
+
const metricsEnabled = opts !== false && opts?.enabled !== false
|
|
290
|
+
const healthProbesEnabled = isHealthProbesEnabled(healthProbes) && useSharedServer(opts, healthProbes)
|
|
291
|
+
const serverOpts = healthProbesEnabled && isHealthProbesServerEnabled(healthProbes) ? resolveHealthProbesOptions(opts, healthProbes) : opts
|
|
292
|
+
|
|
293
|
+
return startServer(runtime, serverOpts, metricsEnabled, healthProbesEnabled)
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
export async function startHealthProbesServer (runtime, metricsOpts, healthProbes) {
|
|
297
|
+
if (!isHealthProbesEnabled(healthProbes) || useSharedServer(metricsOpts, healthProbes)) {
|
|
298
|
+
return
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
return startServer(runtime, resolveHealthProbesOptions(metricsOpts, healthProbes), false, true)
|
|
302
|
+
}
|
package/lib/runtime.js
CHANGED
|
@@ -11,7 +11,11 @@ import {
|
|
|
11
11
|
} from '@platformatic/foundation'
|
|
12
12
|
import { getExecutable } from '@platformatic/globals'
|
|
13
13
|
import { ITC } from '@platformatic/itc'
|
|
14
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
collectProcessMetrics,
|
|
16
|
+
client as metricsClient,
|
|
17
|
+
openTelemetryITCMessage
|
|
18
|
+
} from '@platformatic/metrics'
|
|
15
19
|
import fastify from 'fastify'
|
|
16
20
|
import { EventEmitter, once } from 'node:events'
|
|
17
21
|
import { existsSync } from 'node:fs'
|
|
@@ -45,8 +49,9 @@ import {
|
|
|
45
49
|
import { abstractLogger, createLogger } from './logger.js'
|
|
46
50
|
import { startManagementApi } from './management-api.js'
|
|
47
51
|
import { createManagementHandlers } from './management-handlers.js'
|
|
52
|
+
import { OpenTelemetryMetricsForwarder } from './opentelemetry-metrics.js'
|
|
48
53
|
import { createChannelCreationHook } from './policies.js'
|
|
49
|
-
import { startPrometheusServer } from './prom-server.js'
|
|
54
|
+
import { startHealthProbesServer, startPrometheusServer } from './prom-server.js'
|
|
50
55
|
import { startScheduler } from './scheduler.js'
|
|
51
56
|
import { createSharedStore } from './shared-http-cache.js'
|
|
52
57
|
import { topologicalLevels, topologicalSort } from './utils.js'
|
|
@@ -135,6 +140,8 @@ export class Runtime extends EventEmitter {
|
|
|
135
140
|
|
|
136
141
|
#managementApi
|
|
137
142
|
#prometheusServer
|
|
143
|
+
#healthProbesServer
|
|
144
|
+
#opentelemetryMetricsForwarder
|
|
138
145
|
#inspectorServer
|
|
139
146
|
#metricsLabelName
|
|
140
147
|
|
|
@@ -238,12 +245,17 @@ export class Runtime extends EventEmitter {
|
|
|
238
245
|
if (config.metrics) {
|
|
239
246
|
// Use the configured application label name for metrics (defaults to 'applicationId')
|
|
240
247
|
this.#metricsLabelName = config.metrics.applicationLabel || 'applicationId'
|
|
241
|
-
this.#prometheusServer = await startPrometheusServer(this, config.metrics, config.healthProbes)
|
|
242
248
|
} else {
|
|
243
249
|
// Default to applicationId if metrics are not configured
|
|
244
250
|
this.#metricsLabelName = 'applicationId'
|
|
245
251
|
}
|
|
246
252
|
|
|
253
|
+
if (config.metrics || (typeof config.healthProbes === 'object' && config.healthProbes !== null)) {
|
|
254
|
+
this.#prometheusServer = await startPrometheusServer(this, config.metrics ?? false, config.healthProbes)
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
this.#healthProbesServer = await startHealthProbesServer(this, config.metrics, config.healthProbes)
|
|
258
|
+
|
|
247
259
|
// Initialize process-level metrics registry in the main thread if metrics or management API is enabled
|
|
248
260
|
// These metrics are the same across all workers and only need to be collected once
|
|
249
261
|
// We need this for management API as it can request metrics even without explicit metrics config
|
|
@@ -258,6 +270,8 @@ export class Runtime extends EventEmitter {
|
|
|
258
270
|
this.#loggerDestination = destination
|
|
259
271
|
this.#loggerContext = context
|
|
260
272
|
|
|
273
|
+
await this.#startOpenTelemetryMetricsForwarder(config.metrics?.opentelemetry)
|
|
274
|
+
|
|
261
275
|
this.#createWorkersBroadcastChannel()
|
|
262
276
|
|
|
263
277
|
if (this.#config.workers.dynamic) {
|
|
@@ -407,6 +421,15 @@ export class Runtime extends EventEmitter {
|
|
|
407
421
|
await this.#prometheusServer.close()
|
|
408
422
|
}
|
|
409
423
|
|
|
424
|
+
if (this.#healthProbesServer) {
|
|
425
|
+
await this.#healthProbesServer.close()
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
if (this.#opentelemetryMetricsForwarder) {
|
|
429
|
+
await this.#opentelemetryMetricsForwarder.close()
|
|
430
|
+
this.#opentelemetryMetricsForwarder = null
|
|
431
|
+
}
|
|
432
|
+
|
|
410
433
|
// Clean up process metrics registry
|
|
411
434
|
if (this.#processMetricsRegistry) {
|
|
412
435
|
this.#processMetricsRegistry.clear()
|
|
@@ -864,12 +887,24 @@ export class Runtime extends EventEmitter {
|
|
|
864
887
|
this.#prometheusServer = null
|
|
865
888
|
}
|
|
866
889
|
|
|
890
|
+
if (this.#healthProbesServer) {
|
|
891
|
+
await this.#healthProbesServer.close()
|
|
892
|
+
this.#healthProbesServer = null
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
if (this.#opentelemetryMetricsForwarder) {
|
|
896
|
+
await this.#opentelemetryMetricsForwarder.close()
|
|
897
|
+
this.#opentelemetryMetricsForwarder = null
|
|
898
|
+
}
|
|
899
|
+
|
|
867
900
|
this.#config.metrics = metricsConfig
|
|
868
901
|
this.#metricsLabelName = metricsConfig?.applicationLabel || 'applicationId'
|
|
869
902
|
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
903
|
+
this.#prometheusServer = await startPrometheusServer(this, metricsConfig, this.#config.healthProbes)
|
|
904
|
+
|
|
905
|
+
this.#healthProbesServer = await startHealthProbesServer(this, metricsConfig, this.#config.healthProbes)
|
|
906
|
+
|
|
907
|
+
await this.#startOpenTelemetryMetricsForwarder(metricsConfig?.opentelemetry)
|
|
873
908
|
|
|
874
909
|
const promises = []
|
|
875
910
|
for (const worker of this.#workers.values()) {
|
|
@@ -889,6 +924,17 @@ export class Runtime extends EventEmitter {
|
|
|
889
924
|
return { success: true, config: metricsConfig }
|
|
890
925
|
}
|
|
891
926
|
|
|
927
|
+
async #startOpenTelemetryMetricsForwarder (config) {
|
|
928
|
+
if (!config?.endpoint || config.enabled === false || config.enabled === 'false') {
|
|
929
|
+
return
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
const forwarder = new OpenTelemetryMetricsForwarder(config, this.logger)
|
|
933
|
+
if (await forwarder.start()) {
|
|
934
|
+
this.#opentelemetryMetricsForwarder = forwarder
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
|
|
892
938
|
// TODO: Remove in next major version
|
|
893
939
|
startCollectingMetrics () {
|
|
894
940
|
this.logger.warn(
|
|
@@ -2026,6 +2072,10 @@ export class Runtime extends EventEmitter {
|
|
|
2026
2072
|
worker[kIsSubprocessHost] = true
|
|
2027
2073
|
})
|
|
2028
2074
|
|
|
2075
|
+
worker[kITC].on(openTelemetryITCMessage, resourceMetrics => {
|
|
2076
|
+
this.#opentelemetryMetricsForwarder?.collect(resourceMetrics)
|
|
2077
|
+
})
|
|
2078
|
+
|
|
2029
2079
|
worker[kITC].on('request:restart', async () => {
|
|
2030
2080
|
// Do not restart applications that are not fully started yet or when the runtime is still starting.
|
|
2031
2081
|
// The gateway sends request:restart when it receives application:added events,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@platformatic/runtime",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.61.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
"@fastify/compress": "^8.0.0",
|
|
19
19
|
"@fastify/express": "^4.0.0",
|
|
20
20
|
"@fastify/formbody": "^8.0.0",
|
|
21
|
+
"@opentelemetry/sdk-metrics": "^2.8.0",
|
|
21
22
|
"@sentry/node": "^10.58.0",
|
|
22
23
|
"atomic-sleep": "^1.0.0",
|
|
23
24
|
"autocannon": "^8.0.0",
|
|
@@ -38,14 +39,14 @@
|
|
|
38
39
|
"typescript": "^5.5.4",
|
|
39
40
|
"undici-oidc-interceptor": "^0.9.0",
|
|
40
41
|
"why-is-node-running": "^2.2.2",
|
|
41
|
-
"@platformatic/composer": "3.
|
|
42
|
-
"@platformatic/db": "3.
|
|
43
|
-
"@platformatic/gateway": "3.
|
|
44
|
-
"@platformatic/node": "3.
|
|
45
|
-
"@platformatic/service": "3.
|
|
46
|
-
"@platformatic/sql-
|
|
47
|
-
"@platformatic/
|
|
48
|
-
"@platformatic/
|
|
42
|
+
"@platformatic/composer": "3.61.0",
|
|
43
|
+
"@platformatic/db": "3.61.0",
|
|
44
|
+
"@platformatic/gateway": "3.61.0",
|
|
45
|
+
"@platformatic/node": "3.61.0",
|
|
46
|
+
"@platformatic/service": "3.61.0",
|
|
47
|
+
"@platformatic/sql-graphql": "3.61.0",
|
|
48
|
+
"@platformatic/wattpm-pprof-capture": "3.61.0",
|
|
49
|
+
"@platformatic/sql-mapper": "3.61.0"
|
|
49
50
|
},
|
|
50
51
|
"dependencies": {
|
|
51
52
|
"@fastify/accepts": "^5.0.0",
|
|
@@ -53,6 +54,7 @@
|
|
|
53
54
|
"@fastify/error": "^4.0.0",
|
|
54
55
|
"@fastify/websocket": "^11.0.0",
|
|
55
56
|
"@opentelemetry/api": "^1.9.0",
|
|
57
|
+
"@opentelemetry/exporter-metrics-otlp-proto": "^0.219.0",
|
|
56
58
|
"@platformatic/prom-client": "^1.0.0",
|
|
57
59
|
"@platformatic/undici-cache-memory": "^0.9.0",
|
|
58
60
|
"@watchable/unpromise": "^1.0.2",
|
|
@@ -75,13 +77,13 @@
|
|
|
75
77
|
"undici": "^7.27.2",
|
|
76
78
|
"undici-thread-interceptor": "^1.3.1",
|
|
77
79
|
"ws": "^8.16.0",
|
|
78
|
-
"@platformatic/basic": "3.
|
|
79
|
-
"@platformatic/generators": "3.
|
|
80
|
-
"@platformatic/
|
|
81
|
-
"@platformatic/
|
|
82
|
-
"@platformatic/
|
|
83
|
-
"@platformatic/telemetry": "3.
|
|
84
|
-
"@platformatic/
|
|
80
|
+
"@platformatic/basic": "3.61.0",
|
|
81
|
+
"@platformatic/generators": "3.61.0",
|
|
82
|
+
"@platformatic/foundation": "3.61.0",
|
|
83
|
+
"@platformatic/globals": "3.61.0",
|
|
84
|
+
"@platformatic/itc": "3.61.0",
|
|
85
|
+
"@platformatic/telemetry": "3.61.0",
|
|
86
|
+
"@platformatic/metrics": "3.61.0"
|
|
85
87
|
},
|
|
86
88
|
"engines": {
|
|
87
89
|
"node": ">=22.19.0"
|
package/schema.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"$id": "https://schemas.platformatic.dev/@platformatic/runtime/3.
|
|
2
|
+
"$id": "https://schemas.platformatic.dev/@platformatic/runtime/3.61.0.json",
|
|
3
3
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
4
4
|
"title": "Platformatic Runtime Config",
|
|
5
5
|
"type": "object",
|
|
@@ -2211,6 +2211,115 @@
|
|
|
2211
2211
|
},
|
|
2212
2212
|
{
|
|
2213
2213
|
"type": "string"
|
|
2214
|
+
},
|
|
2215
|
+
{
|
|
2216
|
+
"type": "object",
|
|
2217
|
+
"properties": {
|
|
2218
|
+
"enabled": {
|
|
2219
|
+
"anyOf": [
|
|
2220
|
+
{
|
|
2221
|
+
"type": "boolean"
|
|
2222
|
+
},
|
|
2223
|
+
{
|
|
2224
|
+
"type": "string"
|
|
2225
|
+
}
|
|
2226
|
+
]
|
|
2227
|
+
},
|
|
2228
|
+
"hostname": {
|
|
2229
|
+
"type": "string"
|
|
2230
|
+
},
|
|
2231
|
+
"port": {
|
|
2232
|
+
"anyOf": [
|
|
2233
|
+
{
|
|
2234
|
+
"type": "integer"
|
|
2235
|
+
},
|
|
2236
|
+
{
|
|
2237
|
+
"type": "string"
|
|
2238
|
+
}
|
|
2239
|
+
]
|
|
2240
|
+
},
|
|
2241
|
+
"readiness": {
|
|
2242
|
+
"anyOf": [
|
|
2243
|
+
{
|
|
2244
|
+
"type": "boolean"
|
|
2245
|
+
},
|
|
2246
|
+
{
|
|
2247
|
+
"type": "object",
|
|
2248
|
+
"properties": {
|
|
2249
|
+
"endpoint": {
|
|
2250
|
+
"type": "string"
|
|
2251
|
+
},
|
|
2252
|
+
"success": {
|
|
2253
|
+
"type": "object",
|
|
2254
|
+
"properties": {
|
|
2255
|
+
"statusCode": {
|
|
2256
|
+
"type": "number"
|
|
2257
|
+
},
|
|
2258
|
+
"body": {
|
|
2259
|
+
"type": "string"
|
|
2260
|
+
}
|
|
2261
|
+
},
|
|
2262
|
+
"additionalProperties": false
|
|
2263
|
+
},
|
|
2264
|
+
"fail": {
|
|
2265
|
+
"type": "object",
|
|
2266
|
+
"properties": {
|
|
2267
|
+
"statusCode": {
|
|
2268
|
+
"type": "number"
|
|
2269
|
+
},
|
|
2270
|
+
"body": {
|
|
2271
|
+
"type": "string"
|
|
2272
|
+
}
|
|
2273
|
+
},
|
|
2274
|
+
"additionalProperties": false
|
|
2275
|
+
}
|
|
2276
|
+
},
|
|
2277
|
+
"additionalProperties": false
|
|
2278
|
+
}
|
|
2279
|
+
]
|
|
2280
|
+
},
|
|
2281
|
+
"liveness": {
|
|
2282
|
+
"anyOf": [
|
|
2283
|
+
{
|
|
2284
|
+
"type": "boolean"
|
|
2285
|
+
},
|
|
2286
|
+
{
|
|
2287
|
+
"type": "object",
|
|
2288
|
+
"properties": {
|
|
2289
|
+
"endpoint": {
|
|
2290
|
+
"type": "string"
|
|
2291
|
+
},
|
|
2292
|
+
"success": {
|
|
2293
|
+
"type": "object",
|
|
2294
|
+
"properties": {
|
|
2295
|
+
"statusCode": {
|
|
2296
|
+
"type": "number"
|
|
2297
|
+
},
|
|
2298
|
+
"body": {
|
|
2299
|
+
"type": "string"
|
|
2300
|
+
}
|
|
2301
|
+
},
|
|
2302
|
+
"additionalProperties": false
|
|
2303
|
+
},
|
|
2304
|
+
"fail": {
|
|
2305
|
+
"type": "object",
|
|
2306
|
+
"properties": {
|
|
2307
|
+
"statusCode": {
|
|
2308
|
+
"type": "number"
|
|
2309
|
+
},
|
|
2310
|
+
"body": {
|
|
2311
|
+
"type": "string"
|
|
2312
|
+
}
|
|
2313
|
+
},
|
|
2314
|
+
"additionalProperties": false
|
|
2315
|
+
}
|
|
2316
|
+
},
|
|
2317
|
+
"additionalProperties": false
|
|
2318
|
+
}
|
|
2319
|
+
]
|
|
2320
|
+
}
|
|
2321
|
+
},
|
|
2322
|
+
"additionalProperties": false
|
|
2214
2323
|
}
|
|
2215
2324
|
],
|
|
2216
2325
|
"default": true
|
|
@@ -2687,7 +2796,9 @@
|
|
|
2687
2796
|
"type": "string"
|
|
2688
2797
|
}
|
|
2689
2798
|
],
|
|
2690
|
-
"default": 5000
|
|
2799
|
+
"default": 5000,
|
|
2800
|
+
"deprecated": true,
|
|
2801
|
+
"description": "Deprecated. Health probe timeout configuration is no longer used."
|
|
2691
2802
|
},
|
|
2692
2803
|
"plugins": {
|
|
2693
2804
|
"type": "array",
|
|
@@ -2763,6 +2874,50 @@
|
|
|
2763
2874
|
],
|
|
2764
2875
|
"additionalProperties": false
|
|
2765
2876
|
},
|
|
2877
|
+
"opentelemetry": {
|
|
2878
|
+
"type": "object",
|
|
2879
|
+
"description": "Configuration for forwarding user OpenTelemetry metrics to an OTLP endpoint",
|
|
2880
|
+
"properties": {
|
|
2881
|
+
"enabled": {
|
|
2882
|
+
"anyOf": [
|
|
2883
|
+
{
|
|
2884
|
+
"type": "boolean"
|
|
2885
|
+
},
|
|
2886
|
+
{
|
|
2887
|
+
"type": "string"
|
|
2888
|
+
}
|
|
2889
|
+
],
|
|
2890
|
+
"description": "Enable or disable OpenTelemetry metrics forwarding"
|
|
2891
|
+
},
|
|
2892
|
+
"endpoint": {
|
|
2893
|
+
"type": "string",
|
|
2894
|
+
"description": "OTLP metrics endpoint URL (e.g., http://collector:4318/v1/metrics)"
|
|
2895
|
+
},
|
|
2896
|
+
"interval": {
|
|
2897
|
+
"anyOf": [
|
|
2898
|
+
{
|
|
2899
|
+
"type": "integer"
|
|
2900
|
+
},
|
|
2901
|
+
{
|
|
2902
|
+
"type": "string"
|
|
2903
|
+
}
|
|
2904
|
+
],
|
|
2905
|
+
"default": 60000,
|
|
2906
|
+
"description": "Interval in milliseconds between metric forwards"
|
|
2907
|
+
},
|
|
2908
|
+
"headers": {
|
|
2909
|
+
"type": "object",
|
|
2910
|
+
"additionalProperties": {
|
|
2911
|
+
"type": "string"
|
|
2912
|
+
},
|
|
2913
|
+
"description": "Additional HTTP headers for authentication"
|
|
2914
|
+
}
|
|
2915
|
+
},
|
|
2916
|
+
"required": [
|
|
2917
|
+
"endpoint"
|
|
2918
|
+
],
|
|
2919
|
+
"additionalProperties": false
|
|
2920
|
+
},
|
|
2766
2921
|
"httpCustomLabels": {
|
|
2767
2922
|
"type": "array",
|
|
2768
2923
|
"description": "Custom labels to add to HTTP metrics (http_request_all_duration_seconds). Each label extracts its value from an HTTP request header.",
|