@platformatic/basic 2.5.4 → 2.5.5-alpha.2
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/base.js +60 -21
- package/lib/worker/child-manager.js +8 -0
- package/lib/worker/child-process.js +29 -1
- package/package.json +6 -5
- package/schema.json +1 -1
package/lib/base.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { deepmerge } from '@platformatic/utils'
|
|
2
|
+
import { collectMetrics } from '@platformatic/metrics'
|
|
2
3
|
import { parseCommandString } from 'execa'
|
|
3
4
|
import { spawn } from 'node:child_process'
|
|
4
5
|
import { once } from 'node:events'
|
|
@@ -12,7 +13,7 @@ import { cleanBasePath } from './utils.js'
|
|
|
12
13
|
import { ChildManager } from './worker/child-manager.js'
|
|
13
14
|
|
|
14
15
|
export class BaseStackable {
|
|
15
|
-
|
|
16
|
+
childManager
|
|
16
17
|
#subprocess
|
|
17
18
|
#subprocessStarted
|
|
18
19
|
|
|
@@ -29,6 +30,10 @@ export class BaseStackable {
|
|
|
29
30
|
this.graphqlSchema = null
|
|
30
31
|
this.isEntrypoint = options.context.isEntrypoint
|
|
31
32
|
this.isProduction = options.context.isProduction
|
|
33
|
+
this.metricsRegistry = null
|
|
34
|
+
this.startHttpTimer = null
|
|
35
|
+
this.endHttpTimer = null
|
|
36
|
+
this.clientWs = null
|
|
32
37
|
|
|
33
38
|
// Setup the logger
|
|
34
39
|
const pinoOptions = {
|
|
@@ -85,13 +90,6 @@ export class BaseStackable {
|
|
|
85
90
|
return this
|
|
86
91
|
}
|
|
87
92
|
|
|
88
|
-
async collectMetrics () {
|
|
89
|
-
return {
|
|
90
|
-
defaultMetrics: true,
|
|
91
|
-
httpMetrics: false
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
93
|
async getOpenapiSchema () {
|
|
96
94
|
return this.openapiSchema
|
|
97
95
|
}
|
|
@@ -136,7 +134,7 @@ export class BaseStackable {
|
|
|
136
134
|
|
|
137
135
|
this.logger.debug(`Executing "${command}" ...`)
|
|
138
136
|
|
|
139
|
-
this
|
|
137
|
+
this.childManager = new ChildManager({
|
|
140
138
|
logger: this.logger,
|
|
141
139
|
loader,
|
|
142
140
|
scripts,
|
|
@@ -153,7 +151,7 @@ export class BaseStackable {
|
|
|
153
151
|
})
|
|
154
152
|
|
|
155
153
|
try {
|
|
156
|
-
await this
|
|
154
|
+
await this.childManager.inject()
|
|
157
155
|
|
|
158
156
|
const subprocess = this.spawn(command)
|
|
159
157
|
|
|
@@ -182,15 +180,15 @@ export class BaseStackable {
|
|
|
182
180
|
throw error
|
|
183
181
|
}
|
|
184
182
|
} finally {
|
|
185
|
-
await this
|
|
186
|
-
await this
|
|
183
|
+
await this.childManager.eject()
|
|
184
|
+
await this.childManager.close()
|
|
187
185
|
}
|
|
188
186
|
}
|
|
189
187
|
|
|
190
188
|
async startWithCommand (command, loader) {
|
|
191
189
|
const config = this.configManager.current
|
|
192
190
|
const basePath = config.application?.basePath ? cleanBasePath(config.application?.basePath) : ''
|
|
193
|
-
this
|
|
191
|
+
this.childManager = new ChildManager({
|
|
194
192
|
logger: this.logger,
|
|
195
193
|
loader,
|
|
196
194
|
context: {
|
|
@@ -206,12 +204,12 @@ export class BaseStackable {
|
|
|
206
204
|
}
|
|
207
205
|
})
|
|
208
206
|
|
|
209
|
-
this
|
|
207
|
+
this.childManager.on('config', config => {
|
|
210
208
|
this.subprocessConfig = config
|
|
211
209
|
})
|
|
212
210
|
|
|
213
211
|
try {
|
|
214
|
-
await this
|
|
212
|
+
await this.childManager.inject()
|
|
215
213
|
|
|
216
214
|
this.subprocess = this.spawn(command)
|
|
217
215
|
|
|
@@ -234,35 +232,36 @@ export class BaseStackable {
|
|
|
234
232
|
|
|
235
233
|
this.#subprocessStarted = true
|
|
236
234
|
} catch (e) {
|
|
237
|
-
this
|
|
235
|
+
this.childManager.close('SIGKILL')
|
|
238
236
|
throw new Error(`Cannot execute command "${command}": executable not found`)
|
|
239
237
|
} finally {
|
|
240
|
-
await this
|
|
238
|
+
await this.childManager.eject()
|
|
241
239
|
}
|
|
242
240
|
|
|
243
241
|
// If the process exits prematurely, terminate the thread with the same code
|
|
244
242
|
this.subprocess.on('exit', code => {
|
|
245
243
|
if (this.#subprocessStarted && typeof code === 'number' && code !== 0) {
|
|
246
|
-
this
|
|
244
|
+
this.childManager.close('SIGKILL')
|
|
247
245
|
process.exit(code)
|
|
248
246
|
}
|
|
249
247
|
})
|
|
250
248
|
|
|
251
|
-
const [url] = await once(this
|
|
249
|
+
const [url, clientWs] = await once(this.childManager, 'url')
|
|
252
250
|
this.url = url
|
|
251
|
+
this.clientWs = clientWs
|
|
253
252
|
}
|
|
254
253
|
|
|
255
254
|
async stopCommand () {
|
|
256
255
|
this.#subprocessStarted = false
|
|
257
256
|
const exitPromise = once(this.subprocess, 'exit')
|
|
258
257
|
|
|
259
|
-
this
|
|
258
|
+
this.childManager.close(this.subprocessTerminationSignal ?? 'SIGINT')
|
|
260
259
|
this.subprocess.kill(this.subprocessTerminationSignal ?? 'SIGINT')
|
|
261
260
|
await exitPromise
|
|
262
261
|
}
|
|
263
262
|
|
|
264
263
|
getChildManager () {
|
|
265
|
-
return this
|
|
264
|
+
return this.childManager
|
|
266
265
|
}
|
|
267
266
|
|
|
268
267
|
spawn (command) {
|
|
@@ -273,4 +272,44 @@ export class BaseStackable {
|
|
|
273
272
|
? spawn(command, { cwd: this.root, shell: true, windowsVerbatimArguments: true })
|
|
274
273
|
: spawn(executable, args, { cwd: this.root })
|
|
275
274
|
}
|
|
275
|
+
|
|
276
|
+
async collectMetrics () {
|
|
277
|
+
let metricsConfig = this.options.context.metricsConfig
|
|
278
|
+
if (metricsConfig !== false) {
|
|
279
|
+
metricsConfig = {
|
|
280
|
+
defaultMetrics: true,
|
|
281
|
+
httpMetrics: true,
|
|
282
|
+
...metricsConfig
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
if (this.childManager && this.clientWs) {
|
|
286
|
+
await this.childManager.send(this.clientWs, 'collectMetrics', {
|
|
287
|
+
serviceId: this.id,
|
|
288
|
+
metricsConfig
|
|
289
|
+
})
|
|
290
|
+
return
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
const { registry, startHttpTimer, endHttpTimer } = await collectMetrics(
|
|
294
|
+
this.id,
|
|
295
|
+
metricsConfig
|
|
296
|
+
)
|
|
297
|
+
|
|
298
|
+
this.metricsRegistry = registry
|
|
299
|
+
this.startHttpTimer = startHttpTimer
|
|
300
|
+
this.endHttpTimer = endHttpTimer
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
async getMetrics ({ format } = {}) {
|
|
305
|
+
if (this.childManager && this.clientWs) {
|
|
306
|
+
return this.childManager.send(this.clientWs, 'getMetrics', { format })
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
if (!this.metricsRegistry) return null
|
|
310
|
+
|
|
311
|
+
return format === 'json'
|
|
312
|
+
? await this.metricsRegistry.getMetricsAsJSON()
|
|
313
|
+
: await this.metricsRegistry.metrics()
|
|
314
|
+
}
|
|
276
315
|
}
|
|
@@ -44,6 +44,7 @@ export class ChildManager extends ITC {
|
|
|
44
44
|
#socketPath
|
|
45
45
|
#clients
|
|
46
46
|
#requests
|
|
47
|
+
#currentSender
|
|
47
48
|
#currentClient
|
|
48
49
|
#listener
|
|
49
50
|
#originalNodeOptions
|
|
@@ -97,11 +98,14 @@ export class ChildManager extends ITC {
|
|
|
97
98
|
|
|
98
99
|
ws.on('message', raw => {
|
|
99
100
|
try {
|
|
101
|
+
this.#currentSender = ws
|
|
100
102
|
const message = JSON.parse(raw)
|
|
101
103
|
this.#requests.set(message.reqId, ws)
|
|
102
104
|
this.#listener(message)
|
|
103
105
|
} catch (error) {
|
|
104
106
|
this.#handleUnexpectedError(error, 'Handling a message failed.', exitCodes.MANAGER_MESSAGE_HANDLING_FAILED)
|
|
107
|
+
} finally {
|
|
108
|
+
this.#currentSender = null
|
|
105
109
|
}
|
|
106
110
|
})
|
|
107
111
|
|
|
@@ -182,6 +186,10 @@ export class ChildManager extends ITC {
|
|
|
182
186
|
register(this.#loader, { data: this.#context })
|
|
183
187
|
}
|
|
184
188
|
|
|
189
|
+
emit (...args) {
|
|
190
|
+
super.emit(...args, this.#currentSender)
|
|
191
|
+
}
|
|
192
|
+
|
|
185
193
|
send (client, name, message) {
|
|
186
194
|
this.#currentClient = client
|
|
187
195
|
return super.send(name, message)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ITC } from '@platformatic/itc'
|
|
2
2
|
import { setupNodeHTTPTelemetry } from '@platformatic/telemetry'
|
|
3
3
|
import { createPinoWritable, ensureLoggableError } from '@platformatic/utils'
|
|
4
|
+
import { collectMetrics } from '@platformatic/metrics'
|
|
4
5
|
import { tracingChannel } from 'node:diagnostics_channel'
|
|
5
6
|
import { once } from 'node:events'
|
|
6
7
|
import { readFile } from 'node:fs/promises'
|
|
@@ -81,10 +82,22 @@ export class ChildProcess extends ITC {
|
|
|
81
82
|
#socket
|
|
82
83
|
#child
|
|
83
84
|
#logger
|
|
85
|
+
#metricsRegistry
|
|
84
86
|
#pendingMessages
|
|
85
87
|
|
|
86
88
|
constructor () {
|
|
87
|
-
super({
|
|
89
|
+
super({
|
|
90
|
+
throwOnMissingHandler: false,
|
|
91
|
+
name: `${process.env.PLT_MANAGER_ID}-child-process`,
|
|
92
|
+
handlers: {
|
|
93
|
+
collectMetrics: (...args) => {
|
|
94
|
+
return this.#collectMetrics(...args)
|
|
95
|
+
},
|
|
96
|
+
getMetrics: (...args) => {
|
|
97
|
+
return this.#getMetrics(...args)
|
|
98
|
+
},
|
|
99
|
+
}
|
|
100
|
+
})
|
|
88
101
|
|
|
89
102
|
/* c8 ignore next */
|
|
90
103
|
const protocol = platform() === 'win32' ? 'ws+unix:' : 'ws+unix://'
|
|
@@ -152,6 +165,21 @@ export class ChildProcess extends ITC {
|
|
|
152
165
|
this.#socket.close()
|
|
153
166
|
}
|
|
154
167
|
|
|
168
|
+
async #collectMetrics ({ serviceId, metricsConfig }) {
|
|
169
|
+
const { registry } = await collectMetrics(serviceId, metricsConfig)
|
|
170
|
+
this.#metricsRegistry = registry
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
async #getMetrics ({ format } = {}) {
|
|
174
|
+
if (!this.#metricsRegistry) return null
|
|
175
|
+
|
|
176
|
+
const res = format === 'json'
|
|
177
|
+
? await this.#metricsRegistry.getMetricsAsJSON()
|
|
178
|
+
: await this.#metricsRegistry.metrics()
|
|
179
|
+
|
|
180
|
+
return res
|
|
181
|
+
}
|
|
182
|
+
|
|
155
183
|
#setupLogger () {
|
|
156
184
|
// Since this is executed by user code, make sure we only override this in the main thread
|
|
157
185
|
// The rest will be intercepted by the BaseStackable.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@platformatic/basic",
|
|
3
|
-
"version": "2.5.
|
|
3
|
+
"version": "2.5.5-alpha.2",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -23,10 +23,11 @@
|
|
|
23
23
|
"split2": "^4.2.0",
|
|
24
24
|
"undici": "^6.19.5",
|
|
25
25
|
"ws": "^8.18.0",
|
|
26
|
-
"@platformatic/config": "2.5.
|
|
27
|
-
"@platformatic/
|
|
28
|
-
"@platformatic/
|
|
29
|
-
"@platformatic/
|
|
26
|
+
"@platformatic/config": "2.5.5-alpha.2",
|
|
27
|
+
"@platformatic/telemetry": "2.5.5-alpha.2",
|
|
28
|
+
"@platformatic/itc": "2.5.5-alpha.2",
|
|
29
|
+
"@platformatic/metrics": "2.5.5-alpha.2",
|
|
30
|
+
"@platformatic/utils": "2.5.5-alpha.2"
|
|
30
31
|
},
|
|
31
32
|
"devDependencies": {
|
|
32
33
|
"borp": "^0.17.0",
|
package/schema.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"$id": "https://schemas.platformatic.dev/@platformatic/basic/2.5.
|
|
2
|
+
"$id": "https://schemas.platformatic.dev/@platformatic/basic/2.5.5-alpha.2.json",
|
|
3
3
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
4
4
|
"title": "Platformatic Stackable",
|
|
5
5
|
"type": "object",
|