@platformatic/runtime 1.35.5 → 1.36.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/fixtures/botched-start/platformatic.runtime.json +14 -0
- package/fixtures/botched-start/services/a/platformatic.service.json +14 -0
- package/fixtures/botched-start/services/a/plugin.js +11 -0
- package/fixtures/do-not-restart-on-crash/platformatic.runtime.json +14 -0
- package/fixtures/do-not-restart-on-crash/services/a/platformatic.service.json +14 -0
- package/fixtures/do-not-restart-on-crash/services/a/plugin.js +9 -0
- package/fixtures/restart-on-crash/platformatic.runtime.json +14 -0
- package/fixtures/restart-on-crash/services/a/platformatic.service.json +14 -0
- package/fixtures/restart-on-crash/services/a/plugin.js +9 -0
- package/lib/api-client.js +20 -1
- package/lib/errors.js +1 -0
- package/lib/generator/runtime-generator.js +1 -1
- package/lib/schema.js +7 -0
- package/lib/start.js +61 -60
- package/lib/versions/v1.36.0.js +11 -0
- package/lib/worker.js +4 -4
- package/package.json +14 -13
package/lib/api-client.js
CHANGED
|
@@ -28,15 +28,32 @@ class RuntimeApiClient extends EventEmitter {
|
|
|
28
28
|
super()
|
|
29
29
|
this.setMaxListeners(MAX_LISTENERS_COUNT)
|
|
30
30
|
|
|
31
|
-
this.worker = worker
|
|
32
31
|
this.#configManager = configManager
|
|
33
32
|
this.#runtimeTmpDir = getRuntimeTmpDir(configManager.dirname)
|
|
33
|
+
|
|
34
|
+
this.setWorker(worker)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async setWorker (worker) {
|
|
38
|
+
if (!worker) {
|
|
39
|
+
throw new errors.WorkerIsRequired()
|
|
40
|
+
}
|
|
41
|
+
if (this.worker) {
|
|
42
|
+
this.worker.removeAllListeners('message')
|
|
43
|
+
// Ignore all things that happen after the worker has been replaced
|
|
44
|
+
this.#exitPromise.catch(() => {})
|
|
45
|
+
}
|
|
46
|
+
this.worker = worker
|
|
34
47
|
this.#exitPromise = this.#exitHandler()
|
|
35
48
|
this.worker.on('message', (message) => {
|
|
36
49
|
if (message.operationId) {
|
|
37
50
|
this.emit(message.operationId, message)
|
|
38
51
|
}
|
|
39
52
|
})
|
|
53
|
+
|
|
54
|
+
if (this.started) {
|
|
55
|
+
await this.start()
|
|
56
|
+
}
|
|
40
57
|
}
|
|
41
58
|
|
|
42
59
|
async #getRuntimePackageJson () {
|
|
@@ -72,11 +89,13 @@ class RuntimeApiClient extends EventEmitter {
|
|
|
72
89
|
|
|
73
90
|
async start () {
|
|
74
91
|
const address = await this.#sendCommand('plt:start-services')
|
|
92
|
+
this.started = true
|
|
75
93
|
this.emit('start', address)
|
|
76
94
|
return address
|
|
77
95
|
}
|
|
78
96
|
|
|
79
97
|
async close () {
|
|
98
|
+
this.started = false
|
|
80
99
|
await this.#sendCommand('plt:stop-services')
|
|
81
100
|
|
|
82
101
|
this.worker.postMessage({ command: 'plt:close' })
|
package/lib/errors.js
CHANGED
|
@@ -25,6 +25,7 @@ module.exports = {
|
|
|
25
25
|
FailedToUnlinkManagementApiSocket: createError(`${ERROR_PREFIX}_FAILED_TO_UNLINK_MANAGEMENT_API_SOCKET`, 'Failed to unlink management API socket "%s"'),
|
|
26
26
|
LogFileNotFound: createError(`${ERROR_PREFIX}_LOG_FILE_NOT_FOUND`, 'Log file with index %s not found', 404),
|
|
27
27
|
CannotFindGeneratorForTemplateError: createError(`${ERROR_PREFIX}_CANNOT_FIND_GENERATOR_FOR_TEMPLATE`, 'Cannot find a generator for template "%s"'),
|
|
28
|
+
WorkerIsRequired: createError(`${ERROR_PREFIX}_REQUIRED_WORKER`, 'The worker parameter is required'),
|
|
28
29
|
|
|
29
30
|
// TODO: should remove next one as it's not used anymore
|
|
30
31
|
CannotRemoveServiceOnUpdateError: createError(`${ERROR_PREFIX}_CANNOT_REMOVE_SERVICE_ON_UPDATE`, 'Cannot remove service "%s" when updating a Runtime')
|
|
@@ -90,7 +90,7 @@ class RuntimeGenerator extends BaseGenerator {
|
|
|
90
90
|
this.addServicesDependencies()
|
|
91
91
|
|
|
92
92
|
this.addEnvVars({
|
|
93
|
-
PLT_SERVER_HOSTNAME: '
|
|
93
|
+
PLT_SERVER_HOSTNAME: '127.0.0.1',
|
|
94
94
|
PORT: this.config.port || 3042,
|
|
95
95
|
PLT_SERVER_LOGGER_LEVEL: this.config.logLevel || 'info',
|
|
96
96
|
PLT_MANAGEMENT_API: true
|
package/lib/schema.js
CHANGED
package/lib/start.js
CHANGED
|
@@ -25,6 +25,18 @@ const kWorkerExecArgv = [
|
|
|
25
25
|
kLoaderFile
|
|
26
26
|
]
|
|
27
27
|
|
|
28
|
+
function startWorker ({ config, dirname, runtimeLogsDir }, env) {
|
|
29
|
+
const worker = new Worker(kWorkerFile, {
|
|
30
|
+
/* c8 ignore next */
|
|
31
|
+
execArgv: config.hotReload ? kWorkerExecArgv : [],
|
|
32
|
+
transferList: config.loggingPort ? [config.loggingPort] : [],
|
|
33
|
+
workerData: { config, dirname, runtimeLogsDir },
|
|
34
|
+
env
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
return worker
|
|
38
|
+
}
|
|
39
|
+
|
|
28
40
|
async function buildRuntime (configManager, env = process.env) {
|
|
29
41
|
const config = configManager.current
|
|
30
42
|
|
|
@@ -46,60 +58,48 @@ async function buildRuntime (configManager, env = process.env) {
|
|
|
46
58
|
// The configManager cannot be transferred to the worker, so remove it.
|
|
47
59
|
delete config.configManager
|
|
48
60
|
|
|
49
|
-
|
|
50
|
-
/* c8 ignore next */
|
|
51
|
-
execArgv: config.hotReload ? kWorkerExecArgv : [],
|
|
52
|
-
transferList: config.loggingPort ? [config.loggingPort] : [],
|
|
53
|
-
workerData: { config, dirname, runtimeLogsDir },
|
|
54
|
-
env
|
|
55
|
-
})
|
|
61
|
+
let worker = startWorker({ config, dirname, runtimeLogsDir }, env)
|
|
56
62
|
|
|
57
63
|
let managementApi = null
|
|
58
64
|
|
|
59
|
-
let exited = null
|
|
60
|
-
let isWorkerAlive = true
|
|
61
|
-
worker.on('exit', (code) => {
|
|
62
|
-
// TODO(mcollina): refactor to not set this here
|
|
63
|
-
process.exitCode = code
|
|
64
|
-
isWorkerAlive = false
|
|
65
|
-
configManager.fileWatcher?.stopWatching()
|
|
66
|
-
managementApi?.close()
|
|
67
|
-
if (typeof exited === 'function') {
|
|
68
|
-
exited()
|
|
69
|
-
}
|
|
70
|
-
})
|
|
71
|
-
|
|
72
|
-
worker.on('error', () => {
|
|
73
|
-
// If this is the only 'error' handler, then exit the process as the default
|
|
74
|
-
// behavior. If anything else is listening for errors, then don't exit.
|
|
75
|
-
if (worker.listenerCount('error') === 1) {
|
|
76
|
-
// The error is logged in the worker.
|
|
77
|
-
process.exit(1)
|
|
78
|
-
}
|
|
79
|
-
})
|
|
80
|
-
|
|
81
65
|
if (config.hotReload) {
|
|
82
66
|
/* c8 ignore next 3 */
|
|
83
67
|
process.on('SIGUSR2', () => {
|
|
84
68
|
worker.postMessage({ signal: 'SIGUSR2' })
|
|
85
69
|
})
|
|
86
70
|
|
|
87
|
-
// TODO(mcollina): refactor to not alter globals here
|
|
88
|
-
closeWithGrace((event, cb) => {
|
|
89
|
-
if (isWorkerAlive) {
|
|
90
|
-
worker.postMessage(event)
|
|
91
|
-
exited = cb
|
|
92
|
-
} else {
|
|
93
|
-
setImmediate(cb)
|
|
94
|
-
}
|
|
95
|
-
})
|
|
96
|
-
|
|
97
71
|
/* c8 ignore next 3 */
|
|
98
72
|
configManager.on('update', () => {
|
|
99
73
|
// TODO(cjihrig): Need to clean up and restart the worker.
|
|
100
74
|
})
|
|
101
75
|
}
|
|
102
76
|
|
|
77
|
+
function setupExit () {
|
|
78
|
+
worker.on('exit', (code) => {
|
|
79
|
+
// runtimeApiClient.started can be false if a stop command was issued
|
|
80
|
+
// via the management API.
|
|
81
|
+
if (config.restartOnError === false || !runtimeApiClient.started) {
|
|
82
|
+
// We must stop those here in case the `closeWithGrace` callback
|
|
83
|
+
// was not called.
|
|
84
|
+
configManager.fileWatcher?.stopWatching()
|
|
85
|
+
managementApi?.close()
|
|
86
|
+
return
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
worker = startWorker({ config, dirname, runtimeLogsDir }, env)
|
|
90
|
+
setupExit()
|
|
91
|
+
|
|
92
|
+
once(worker, 'message').then((msg) => {
|
|
93
|
+
runtimeApiClient.setWorker(worker).catch(() => {
|
|
94
|
+
// TODO: currently we restart if the worker fails to start intermitently
|
|
95
|
+
// should we limit this to a number of retries?
|
|
96
|
+
})
|
|
97
|
+
})
|
|
98
|
+
})
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
setupExit()
|
|
102
|
+
|
|
103
103
|
await once(worker, 'message') // plt:init
|
|
104
104
|
|
|
105
105
|
const runtimeApiClient = new RuntimeApiClient(
|
|
@@ -151,7 +151,16 @@ async function startCommand (args) {
|
|
|
151
151
|
runtime = await buildRuntime(wrappedConfig)
|
|
152
152
|
}
|
|
153
153
|
|
|
154
|
-
|
|
154
|
+
const res = await runtime.start()
|
|
155
|
+
|
|
156
|
+
closeWithGrace(async (event) => {
|
|
157
|
+
if (event.err instanceof Error) {
|
|
158
|
+
console.error(event.err)
|
|
159
|
+
}
|
|
160
|
+
await runtime.close()
|
|
161
|
+
})
|
|
162
|
+
|
|
163
|
+
return res
|
|
155
164
|
} catch (err) {
|
|
156
165
|
if (err.code === 'PLT_CONFIG_NO_CONFIG_FILE_FOUND' && args.length === 1) {
|
|
157
166
|
const config = {
|
|
@@ -176,32 +185,24 @@ async function startCommand (args) {
|
|
|
176
185
|
await writeFile(toWrite, JSON.stringify(config, null, 2))
|
|
177
186
|
return startCommand(['--config', toWrite])
|
|
178
187
|
}
|
|
179
|
-
logErrorAndExit(err)
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
188
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
Be sure to have a config file with one of the following names:
|
|
189
|
+
if (err.filenames) {
|
|
190
|
+
console.error(`Missing config file!
|
|
191
|
+
Be sure to have a config file with one of the following names:
|
|
187
192
|
|
|
188
|
-
${err.filenames.map((s) => ' * ' + s).join('\n')}
|
|
193
|
+
${err.filenames.map((s) => ' * ' + s).join('\n')}
|
|
189
194
|
|
|
190
|
-
In alternative run "npm create platformatic@latest" to generate a basic plt service config.`)
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
195
|
+
In alternative run "npm create platformatic@latest" to generate a basic plt service config.`)
|
|
196
|
+
process.exit(1)
|
|
197
|
+
} else if (err.validationErrors) {
|
|
198
|
+
printConfigValidationErrors(err)
|
|
199
|
+
process.exit(1)
|
|
200
|
+
}
|
|
196
201
|
|
|
197
|
-
|
|
198
|
-
console.error(err?.message)
|
|
202
|
+
console.error(err)
|
|
199
203
|
|
|
200
|
-
|
|
201
|
-
console.error(`${err.cause}`)
|
|
204
|
+
process.exit(1)
|
|
202
205
|
}
|
|
203
|
-
|
|
204
|
-
process.exit(1)
|
|
205
206
|
}
|
|
206
207
|
|
|
207
208
|
module.exports = { buildRuntime, start, startCommand }
|
package/lib/worker.js
CHANGED
|
@@ -98,10 +98,10 @@ process.on('uncaughtException', (err) => {
|
|
|
98
98
|
|
|
99
99
|
if (stop) {
|
|
100
100
|
stop().then(() => {
|
|
101
|
-
process.exit(1)
|
|
101
|
+
setImmediate(process.exit.bind(process), 1)
|
|
102
102
|
})
|
|
103
103
|
} else {
|
|
104
|
-
process.exit(1)
|
|
104
|
+
setImmediate(process.exit.bind(process), 1)
|
|
105
105
|
}
|
|
106
106
|
})
|
|
107
107
|
|
|
@@ -112,10 +112,10 @@ process.on('unhandledRejection', (err) => {
|
|
|
112
112
|
|
|
113
113
|
if (stop) {
|
|
114
114
|
stop().then(() => {
|
|
115
|
-
process.exit(1)
|
|
115
|
+
setImmediate(process.exit.bind(process), 1)
|
|
116
116
|
})
|
|
117
117
|
} else {
|
|
118
|
-
process.exit(1)
|
|
118
|
+
setImmediate(process.exit.bind(process), 1)
|
|
119
119
|
}
|
|
120
120
|
})
|
|
121
121
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@platformatic/runtime",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.36.1",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
},
|
|
18
18
|
"homepage": "https://github.com/platformatic/platformatic#readme",
|
|
19
19
|
"devDependencies": {
|
|
20
|
-
"@fastify/express": "^
|
|
20
|
+
"@fastify/express": "^3.0.0",
|
|
21
21
|
"@fastify/formbody": "^7.4.0",
|
|
22
22
|
"@matteo.collina/tspl": "^0.1.1",
|
|
23
23
|
"borp": "^0.11.0",
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
"execa": "^8.0.1",
|
|
26
26
|
"express": "^4.18.3",
|
|
27
27
|
"fast-jwt": "^3.3.3",
|
|
28
|
+
"get-port": "^7.1.0",
|
|
28
29
|
"pino-abstract-transport": "^1.1.0",
|
|
29
30
|
"snazzy": "^9.0.0",
|
|
30
31
|
"split2": "^4.2.0",
|
|
@@ -33,11 +34,10 @@
|
|
|
33
34
|
"typescript": "^5.4.2",
|
|
34
35
|
"undici-oidc-interceptor": "^0.5.0",
|
|
35
36
|
"why-is-node-running": "^2.2.2",
|
|
36
|
-
"@platformatic/sql-graphql": "1.
|
|
37
|
-
"@platformatic/sql-mapper": "1.
|
|
37
|
+
"@platformatic/sql-graphql": "1.36.1",
|
|
38
|
+
"@platformatic/sql-mapper": "1.36.1"
|
|
38
39
|
},
|
|
39
40
|
"dependencies": {
|
|
40
|
-
"ws": "^8.16.0",
|
|
41
41
|
"@fastify/error": "^3.4.1",
|
|
42
42
|
"@fastify/websocket": "^10.0.0",
|
|
43
43
|
"@hapi/topo": "^6.0.2",
|
|
@@ -57,18 +57,19 @@
|
|
|
57
57
|
"minimist": "^1.2.8",
|
|
58
58
|
"pino": "^8.19.0",
|
|
59
59
|
"pino-pretty": "^10.3.1",
|
|
60
|
-
"semgrator": "^0.3.0",
|
|
61
60
|
"pino-roll": "^1.0.0",
|
|
61
|
+
"semgrator": "^0.3.0",
|
|
62
62
|
"tail-file-stream": "^0.1.0",
|
|
63
63
|
"undici": "^6.9.0",
|
|
64
64
|
"why-is-node-running": "^2.2.2",
|
|
65
|
-
"
|
|
66
|
-
"@platformatic/
|
|
67
|
-
"@platformatic/
|
|
68
|
-
"@platformatic/
|
|
69
|
-
"@platformatic/
|
|
70
|
-
"@platformatic/
|
|
71
|
-
"@platformatic/
|
|
65
|
+
"ws": "^8.16.0",
|
|
66
|
+
"@platformatic/composer": "1.36.1",
|
|
67
|
+
"@platformatic/config": "1.36.1",
|
|
68
|
+
"@platformatic/db": "1.36.1",
|
|
69
|
+
"@platformatic/generators": "1.36.1",
|
|
70
|
+
"@platformatic/service": "1.36.1",
|
|
71
|
+
"@platformatic/telemetry": "1.36.1",
|
|
72
|
+
"@platformatic/utils": "1.36.1"
|
|
72
73
|
},
|
|
73
74
|
"standard": {
|
|
74
75
|
"ignore": [
|