@platformatic/runtime 3.8.0 → 3.9.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/lib/management-api.js +2 -1
- package/lib/runtime.js +2 -2
- package/lib/worker/controller.js +49 -24
- package/lib/worker/itc.js +2 -2
- package/lib/worker/main.js +24 -57
- package/package.json +16 -15
- package/schema.json +1 -1
package/lib/management-api.js
CHANGED
|
@@ -126,7 +126,8 @@ export async function managementApiPlugin (app, opts) {
|
|
|
126
126
|
const { id } = request.params
|
|
127
127
|
app.log.debug('stop profiling', { id })
|
|
128
128
|
|
|
129
|
-
const
|
|
129
|
+
const options = request.body || {}
|
|
130
|
+
const profileData = await runtime.stopApplicationProfiling(id, options)
|
|
130
131
|
reply.type('application/octet-stream').code(200).send(profileData)
|
|
131
132
|
})
|
|
132
133
|
|
package/lib/runtime.js
CHANGED
|
@@ -562,11 +562,11 @@ export class Runtime extends EventEmitter {
|
|
|
562
562
|
return sendViaITC(service, 'startProfiling', options)
|
|
563
563
|
}
|
|
564
564
|
|
|
565
|
-
async stopApplicationProfiling (id, ensureStarted = true) {
|
|
565
|
+
async stopApplicationProfiling (id, options = {}, ensureStarted = true) {
|
|
566
566
|
const service = await this.#getApplicationById(id, ensureStarted)
|
|
567
567
|
this.#validatePprofCapturePreload()
|
|
568
568
|
|
|
569
|
-
return sendViaITC(service, 'stopProfiling')
|
|
569
|
+
return sendViaITC(service, 'stopProfiling', options)
|
|
570
570
|
}
|
|
571
571
|
|
|
572
572
|
async updateUndiciInterceptors (undiciConfig) {
|
package/lib/worker/controller.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ensureLoggableError,
|
|
3
|
+
executeWithTimeout,
|
|
3
4
|
FileWatcher,
|
|
4
5
|
kHandledError,
|
|
5
6
|
listRecognizedConfigurationFiles,
|
|
@@ -24,6 +25,21 @@ function fetchApplicationUrl (application, key) {
|
|
|
24
25
|
return getApplicationUrl(application.id)
|
|
25
26
|
}
|
|
26
27
|
|
|
28
|
+
function handleUnhandled (app, type, err) {
|
|
29
|
+
const label =
|
|
30
|
+
workerData.worker.count > 1
|
|
31
|
+
? `worker ${workerData.worker.index} of the application "${workerData.applicationConfig.id}"`
|
|
32
|
+
: `application "${workerData.applicationConfig.id}"`
|
|
33
|
+
|
|
34
|
+
globalThis.platformatic.logger.error({ err: ensureLoggableError(err) }, `The ${label} threw an ${type}.`)
|
|
35
|
+
|
|
36
|
+
executeWithTimeout(app?.stop(), 1000)
|
|
37
|
+
.catch()
|
|
38
|
+
.finally(() => {
|
|
39
|
+
process.exit(1)
|
|
40
|
+
})
|
|
41
|
+
}
|
|
42
|
+
|
|
27
43
|
export class Controller extends EventEmitter {
|
|
28
44
|
#starting
|
|
29
45
|
#started
|
|
@@ -34,21 +50,13 @@ export class Controller extends EventEmitter {
|
|
|
34
50
|
#context
|
|
35
51
|
#lastELU
|
|
36
52
|
|
|
37
|
-
constructor (
|
|
38
|
-
appConfig,
|
|
39
|
-
workerId,
|
|
40
|
-
telemetryConfig,
|
|
41
|
-
loggerConfig,
|
|
42
|
-
serverConfig,
|
|
43
|
-
metricsConfig,
|
|
44
|
-
hasManagementApi,
|
|
45
|
-
watch
|
|
46
|
-
) {
|
|
53
|
+
constructor (runtimeConfig, applicationConfig, workerId, serverConfig, metricsConfig) {
|
|
47
54
|
super()
|
|
48
|
-
this.
|
|
49
|
-
this.
|
|
55
|
+
this.runtimeConfig = runtimeConfig
|
|
56
|
+
this.applicationConfig = applicationConfig
|
|
57
|
+
this.applicationId = this.applicationConfig.id
|
|
50
58
|
this.workerId = workerId
|
|
51
|
-
this.#watch = watch
|
|
59
|
+
this.#watch = !!runtimeConfig.watch
|
|
52
60
|
this.#starting = false
|
|
53
61
|
this.#started = false
|
|
54
62
|
this.#listening = false
|
|
@@ -60,17 +68,17 @@ export class Controller extends EventEmitter {
|
|
|
60
68
|
controller: this,
|
|
61
69
|
applicationId: this.applicationId,
|
|
62
70
|
workerId: this.workerId,
|
|
63
|
-
directory: this.
|
|
64
|
-
dependencies: this.
|
|
65
|
-
isEntrypoint: this.
|
|
66
|
-
isProduction: this.
|
|
67
|
-
telemetryConfig,
|
|
71
|
+
directory: this.applicationConfig.path,
|
|
72
|
+
dependencies: this.applicationConfig.dependencies,
|
|
73
|
+
isEntrypoint: this.applicationConfig.entrypoint,
|
|
74
|
+
isProduction: this.applicationConfig.isProduction,
|
|
75
|
+
telemetryConfig: this.applicationConfig.telemetry,
|
|
76
|
+
loggerConfig: runtimeConfig.logger,
|
|
68
77
|
metricsConfig,
|
|
69
|
-
loggerConfig,
|
|
70
78
|
serverConfig,
|
|
71
79
|
worker: workerData?.worker,
|
|
72
|
-
hasManagementApi: !!
|
|
73
|
-
fetchApplicationUrl: fetchApplicationUrl.bind(null,
|
|
80
|
+
hasManagementApi: !!runtimeConfig.managementApi,
|
|
81
|
+
fetchApplicationUrl: fetchApplicationUrl.bind(null, applicationConfig)
|
|
74
82
|
}
|
|
75
83
|
}
|
|
76
84
|
|
|
@@ -90,7 +98,7 @@ export class Controller extends EventEmitter {
|
|
|
90
98
|
// Note: capability's init() is executed within start
|
|
91
99
|
async init () {
|
|
92
100
|
try {
|
|
93
|
-
const appConfig = this.
|
|
101
|
+
const appConfig = this.applicationConfig
|
|
94
102
|
|
|
95
103
|
if (appConfig.isProduction && !process.env.NODE_ENV) {
|
|
96
104
|
process.env.NODE_ENV = 'production'
|
|
@@ -120,6 +128,10 @@ export class Controller extends EventEmitter {
|
|
|
120
128
|
}
|
|
121
129
|
|
|
122
130
|
this.#updateDispatcher()
|
|
131
|
+
|
|
132
|
+
if (this.capability.exitOnUnhandledErrors && this.runtimeConfig.exitOnUnhandledErrors) {
|
|
133
|
+
this.#setupHandlers()
|
|
134
|
+
}
|
|
123
135
|
} catch (err) {
|
|
124
136
|
if (err.validationErrors) {
|
|
125
137
|
globalThis.platformatic.logger.error(
|
|
@@ -168,7 +180,7 @@ export class Controller extends EventEmitter {
|
|
|
168
180
|
}
|
|
169
181
|
}
|
|
170
182
|
|
|
171
|
-
const listen = !!this.
|
|
183
|
+
const listen = !!this.applicationConfig.useHttp
|
|
172
184
|
|
|
173
185
|
try {
|
|
174
186
|
await this.capability.start({ listen })
|
|
@@ -203,7 +215,7 @@ export class Controller extends EventEmitter {
|
|
|
203
215
|
|
|
204
216
|
async listen () {
|
|
205
217
|
// This server is not an entrypoint or already listened in start. Behave as no-op.
|
|
206
|
-
if (!this.
|
|
218
|
+
if (!this.applicationConfig.entrypoint || this.applicationConfig.useHttp || this.#listening) {
|
|
207
219
|
return
|
|
208
220
|
}
|
|
209
221
|
|
|
@@ -299,4 +311,17 @@ export class Controller extends EventEmitter {
|
|
|
299
311
|
|
|
300
312
|
setGlobalDispatcher(dispatcher)
|
|
301
313
|
}
|
|
314
|
+
|
|
315
|
+
#setupHandlers () {
|
|
316
|
+
process.on('uncaughtException', handleUnhandled.bind(null, this, 'uncaught exception'))
|
|
317
|
+
process.on('unhandledRejection', handleUnhandled.bind(null, this, 'unhandled rejection'))
|
|
318
|
+
|
|
319
|
+
process.on('newListener', event => {
|
|
320
|
+
if (event === 'uncaughtException' || event === 'unhandledRejection') {
|
|
321
|
+
globalThis.platformatic.logger.warn(
|
|
322
|
+
`A listener has been added for the "process.${event}" event. This listener will be never triggered as Watt default behavior will kill the process before.\n To disable this behavior, set "exitOnUnhandledErrors" to false in the runtime config.`
|
|
323
|
+
)
|
|
324
|
+
}
|
|
325
|
+
})
|
|
326
|
+
}
|
|
302
327
|
}
|
package/lib/worker/itc.js
CHANGED
|
@@ -71,7 +71,7 @@ export async function waitEventFromITC (worker, event) {
|
|
|
71
71
|
|
|
72
72
|
export function setupITC (controller, application, dispatcher, sharedContext) {
|
|
73
73
|
const logger = globalThis.platformatic.logger
|
|
74
|
-
const messaging = new MessagingITC(controller.
|
|
74
|
+
const messaging = new MessagingITC(controller.applicationConfig.id, workerData.config, logger)
|
|
75
75
|
|
|
76
76
|
Object.assign(globalThis.platformatic ?? {}, {
|
|
77
77
|
messaging: {
|
|
@@ -82,7 +82,7 @@ export function setupITC (controller, application, dispatcher, sharedContext) {
|
|
|
82
82
|
})
|
|
83
83
|
|
|
84
84
|
const itc = new ITC({
|
|
85
|
-
name: controller.
|
|
85
|
+
name: controller.applicationConfig.id + '-worker',
|
|
86
86
|
port: parentPort,
|
|
87
87
|
handlers: {
|
|
88
88
|
async start () {
|
package/lib/worker/main.js
CHANGED
|
@@ -2,8 +2,6 @@ import {
|
|
|
2
2
|
buildPinoFormatters,
|
|
3
3
|
buildPinoTimestamp,
|
|
4
4
|
disablePinoDirectWrite,
|
|
5
|
-
ensureLoggableError,
|
|
6
|
-
executeWithTimeout,
|
|
7
5
|
getPrivateSymbol
|
|
8
6
|
} from '@platformatic/foundation'
|
|
9
7
|
import dotenv from 'dotenv'
|
|
@@ -30,21 +28,6 @@ class ForwardingEventEmitter extends EventEmitter {
|
|
|
30
28
|
}
|
|
31
29
|
}
|
|
32
30
|
|
|
33
|
-
function handleUnhandled (app, type, err) {
|
|
34
|
-
const label =
|
|
35
|
-
workerData.worker.count > 1
|
|
36
|
-
? `worker ${workerData.worker.index} of the application "${workerData.applicationConfig.id}"`
|
|
37
|
-
: `application "${workerData.applicationConfig.id}"`
|
|
38
|
-
|
|
39
|
-
globalThis.platformatic.logger.error({ err: ensureLoggableError(err) }, `The ${label} threw an ${type}.`)
|
|
40
|
-
|
|
41
|
-
executeWithTimeout(app?.stop(), 1000)
|
|
42
|
-
.catch()
|
|
43
|
-
.finally(() => {
|
|
44
|
-
process.exit(1)
|
|
45
|
-
})
|
|
46
|
-
}
|
|
47
|
-
|
|
48
31
|
function patchLogging () {
|
|
49
32
|
disablePinoDirectWrite()
|
|
50
33
|
|
|
@@ -113,16 +96,16 @@ async function main () {
|
|
|
113
96
|
events: new ForwardingEventEmitter()
|
|
114
97
|
})
|
|
115
98
|
|
|
116
|
-
const
|
|
99
|
+
const runtimeConfig = workerData.config
|
|
117
100
|
|
|
118
|
-
await performPreloading(
|
|
101
|
+
await performPreloading(runtimeConfig, workerData.applicationConfig)
|
|
119
102
|
|
|
120
|
-
const
|
|
103
|
+
const applicationConfig = workerData.applicationConfig
|
|
121
104
|
|
|
122
105
|
// Load env file and mixin env vars from application config
|
|
123
106
|
let envfile
|
|
124
|
-
if (
|
|
125
|
-
envfile = resolve(workerData.dirname,
|
|
107
|
+
if (applicationConfig.envfile) {
|
|
108
|
+
envfile = resolve(workerData.dirname, applicationConfig.envfile)
|
|
126
109
|
} else {
|
|
127
110
|
envfile = resolve(workerData.applicationConfig.path, '.env')
|
|
128
111
|
}
|
|
@@ -133,20 +116,20 @@ async function main () {
|
|
|
133
116
|
path: envfile
|
|
134
117
|
})
|
|
135
118
|
|
|
136
|
-
if (
|
|
137
|
-
Object.assign(process.env,
|
|
119
|
+
if (runtimeConfig.env) {
|
|
120
|
+
Object.assign(process.env, runtimeConfig.env)
|
|
138
121
|
}
|
|
139
|
-
if (
|
|
140
|
-
Object.assign(process.env,
|
|
122
|
+
if (applicationConfig.env) {
|
|
123
|
+
Object.assign(process.env, applicationConfig.env)
|
|
141
124
|
}
|
|
142
125
|
|
|
143
|
-
const { threadDispatcher } = await setDispatcher(
|
|
126
|
+
const { threadDispatcher } = await setDispatcher(runtimeConfig)
|
|
144
127
|
|
|
145
128
|
// If the application is an entrypoint and runtime server config is defined, use it.
|
|
146
129
|
let serverConfig = null
|
|
147
|
-
if (
|
|
148
|
-
serverConfig =
|
|
149
|
-
} else if (
|
|
130
|
+
if (runtimeConfig.server && applicationConfig.entrypoint) {
|
|
131
|
+
serverConfig = runtimeConfig.server
|
|
132
|
+
} else if (applicationConfig.useHttp) {
|
|
150
133
|
serverConfig = {
|
|
151
134
|
port: 0,
|
|
152
135
|
hostname: '127.0.0.1',
|
|
@@ -169,48 +152,32 @@ async function main () {
|
|
|
169
152
|
const res = await fetch(url)
|
|
170
153
|
const [{ devtoolsFrontendUrl }] = await res.json()
|
|
171
154
|
|
|
172
|
-
console.log(`For ${
|
|
155
|
+
console.log(`For ${applicationConfig.id} debugger open the following in chrome: "${devtoolsFrontendUrl}"`)
|
|
173
156
|
}
|
|
174
157
|
|
|
175
158
|
// Create the application
|
|
176
159
|
// Add idLabel to metrics config to determine which label name to use (defaults to applicationId)
|
|
177
|
-
const metricsConfig =
|
|
160
|
+
const metricsConfig = runtimeConfig.metrics
|
|
178
161
|
? {
|
|
179
|
-
...
|
|
180
|
-
idLabel:
|
|
162
|
+
...runtimeConfig.metrics,
|
|
163
|
+
idLabel: runtimeConfig.metrics.applicationLabel || 'applicationId'
|
|
181
164
|
}
|
|
182
|
-
:
|
|
165
|
+
: runtimeConfig.metrics
|
|
183
166
|
|
|
184
167
|
const controller = new Controller(
|
|
185
|
-
|
|
168
|
+
runtimeConfig,
|
|
169
|
+
applicationConfig,
|
|
186
170
|
workerData.worker.count > 1 ? workerData.worker.index : undefined,
|
|
187
|
-
application.telemetry,
|
|
188
|
-
config.logger,
|
|
189
171
|
serverConfig,
|
|
190
|
-
metricsConfig
|
|
191
|
-
!!config.managementApi,
|
|
192
|
-
!!config.watch
|
|
172
|
+
metricsConfig
|
|
193
173
|
)
|
|
194
174
|
|
|
195
|
-
if (config.exitOnUnhandledErrors) {
|
|
196
|
-
process.on('uncaughtException', handleUnhandled.bind(null, controller, 'uncaught exception'))
|
|
197
|
-
process.on('unhandledRejection', handleUnhandled.bind(null, controller, 'unhandled rejection'))
|
|
198
|
-
|
|
199
|
-
process.on('newListener', event => {
|
|
200
|
-
if (event === 'uncaughtException' || event === 'unhandledRejection') {
|
|
201
|
-
globalThis.platformatic.logger.warn(
|
|
202
|
-
`A listener has been added for the "process.${event}" event. This listener will be never triggered as Watt default behavior will kill the process before.\n To disable this behavior, set "exitOnUnhandledErrors" to false in the runtime config.`
|
|
203
|
-
)
|
|
204
|
-
}
|
|
205
|
-
})
|
|
206
|
-
}
|
|
207
|
-
|
|
208
175
|
await controller.init()
|
|
209
176
|
|
|
210
|
-
if (
|
|
177
|
+
if (applicationConfig.entrypoint && runtimeConfig.basePath) {
|
|
211
178
|
const meta = await controller.capability.getMeta()
|
|
212
179
|
if (!meta.gateway.wantsAbsoluteUrls) {
|
|
213
|
-
stripBasePath(
|
|
180
|
+
stripBasePath(runtimeConfig.basePath)
|
|
214
181
|
}
|
|
215
182
|
}
|
|
216
183
|
|
|
@@ -222,7 +189,7 @@ async function main () {
|
|
|
222
189
|
}
|
|
223
190
|
|
|
224
191
|
// Setup interaction with parent port
|
|
225
|
-
const itc = setupITC(controller,
|
|
192
|
+
const itc = setupITC(controller, applicationConfig, threadDispatcher, sharedContext)
|
|
226
193
|
globalThis[kITC] = itc
|
|
227
194
|
globalThis.platformatic.itc = itc
|
|
228
195
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@platformatic/runtime",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.9.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
"@fastify/express": "^4.0.0",
|
|
20
20
|
"@fastify/formbody": "^8.0.0",
|
|
21
21
|
"autocannon": "^8.0.0",
|
|
22
|
+
"atomic-sleep": "^1.0.0",
|
|
22
23
|
"c8": "^10.0.0",
|
|
23
24
|
"cleaner-spec-reporter": "^0.5.0",
|
|
24
25
|
"eslint": "9",
|
|
@@ -34,14 +35,14 @@
|
|
|
34
35
|
"typescript": "^5.5.4",
|
|
35
36
|
"undici-oidc-interceptor": "^0.5.0",
|
|
36
37
|
"why-is-node-running": "^2.2.2",
|
|
37
|
-
"@platformatic/composer": "3.
|
|
38
|
-
"@platformatic/db": "3.
|
|
39
|
-
"@platformatic/gateway": "3.
|
|
40
|
-
"@platformatic/
|
|
41
|
-
"@platformatic/
|
|
42
|
-
"@platformatic/
|
|
43
|
-
"@platformatic/
|
|
44
|
-
"@platformatic/wattpm-pprof-capture": "3.
|
|
38
|
+
"@platformatic/composer": "3.9.0",
|
|
39
|
+
"@platformatic/db": "3.9.0",
|
|
40
|
+
"@platformatic/gateway": "3.9.0",
|
|
41
|
+
"@platformatic/sql-graphql": "3.9.0",
|
|
42
|
+
"@platformatic/node": "3.9.0",
|
|
43
|
+
"@platformatic/sql-mapper": "3.9.0",
|
|
44
|
+
"@platformatic/service": "3.9.0",
|
|
45
|
+
"@platformatic/wattpm-pprof-capture": "3.9.0"
|
|
45
46
|
},
|
|
46
47
|
"dependencies": {
|
|
47
48
|
"@fastify/accepts": "^5.0.0",
|
|
@@ -71,12 +72,12 @@
|
|
|
71
72
|
"undici": "^7.0.0",
|
|
72
73
|
"undici-thread-interceptor": "^0.14.0",
|
|
73
74
|
"ws": "^8.16.0",
|
|
74
|
-
"@platformatic/
|
|
75
|
-
"@platformatic/
|
|
76
|
-
"@platformatic/itc": "3.
|
|
77
|
-
"@platformatic/
|
|
78
|
-
"@platformatic/
|
|
79
|
-
"@platformatic/telemetry": "3.
|
|
75
|
+
"@platformatic/foundation": "3.9.0",
|
|
76
|
+
"@platformatic/generators": "3.9.0",
|
|
77
|
+
"@platformatic/itc": "3.9.0",
|
|
78
|
+
"@platformatic/basic": "3.9.0",
|
|
79
|
+
"@platformatic/metrics": "3.9.0",
|
|
80
|
+
"@platformatic/telemetry": "3.9.0"
|
|
80
81
|
},
|
|
81
82
|
"engines": {
|
|
82
83
|
"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.9.0.json",
|
|
3
3
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
4
4
|
"title": "Platformatic Runtime Config",
|
|
5
5
|
"type": "object",
|