@platformatic/runtime 2.0.0-alpha.7 → 2.0.0-alpha.9
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 +4 -1
- package/lib/build-server.js +8 -4
- package/lib/runtime.js +63 -31
- package/lib/schema.js +92 -96
- package/lib/start.js +19 -8
- package/lib/worker/app.js +11 -7
- package/lib/worker/default-stackable.js +1 -0
- package/lib/worker/itc.js +5 -0
- package/lib/worker/main.js +11 -10
- package/package.json +18 -18
- package/schema.json +4 -1
package/config.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* and run json-schema-to-typescript to regenerate this file.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
export type
|
|
8
|
+
export type HttpsSchemasPlatformaticDevPlatformaticRuntime200Alpha9Json = {
|
|
9
9
|
[k: string]: unknown;
|
|
10
10
|
} & {
|
|
11
11
|
$schema?: string;
|
|
@@ -77,6 +77,9 @@ export type HttpsSchemasPlatformaticDevPlatformaticRuntime200Alpha7Json = {
|
|
|
77
77
|
};
|
|
78
78
|
[k: string]: unknown;
|
|
79
79
|
};
|
|
80
|
+
loggerInstance?: {
|
|
81
|
+
[k: string]: unknown;
|
|
82
|
+
};
|
|
80
83
|
serializerOpts?: {
|
|
81
84
|
schema?: {
|
|
82
85
|
[k: string]: unknown;
|
package/lib/build-server.js
CHANGED
|
@@ -9,7 +9,7 @@ const { platformaticRuntime } = require('./config')
|
|
|
9
9
|
const { buildRuntime } = require('./start')
|
|
10
10
|
const { loadConfig } = require('./utils')
|
|
11
11
|
|
|
12
|
-
async function buildServerRuntime (options = {}) {
|
|
12
|
+
async function buildServerRuntime (options = {}, args = undefined) {
|
|
13
13
|
const { serviceMap } = options
|
|
14
14
|
|
|
15
15
|
if (!options.configManager) {
|
|
@@ -18,7 +18,7 @@ async function buildServerRuntime (options = {}) {
|
|
|
18
18
|
// Instantiate a new config manager from the current options.
|
|
19
19
|
const cm = new ConfigManager({
|
|
20
20
|
...platformaticRuntime.configManagerConfig,
|
|
21
|
-
source: options
|
|
21
|
+
source: options
|
|
22
22
|
})
|
|
23
23
|
await cm.parseAndValidate()
|
|
24
24
|
|
|
@@ -31,10 +31,14 @@ async function buildServerRuntime (options = {}) {
|
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
+
if (args) {
|
|
35
|
+
options.configManager.args = args
|
|
36
|
+
}
|
|
37
|
+
|
|
34
38
|
return buildRuntime(options.configManager, options.env)
|
|
35
39
|
}
|
|
36
40
|
|
|
37
|
-
async function buildServer (options) {
|
|
41
|
+
async function buildServer (options, args) {
|
|
38
42
|
if (typeof options === 'string') {
|
|
39
43
|
const config = await loadConfig({}, ['-c', options])
|
|
40
44
|
options = config.configManager.current
|
|
@@ -47,7 +51,7 @@ async function buildServer (options) {
|
|
|
47
51
|
delete options.app
|
|
48
52
|
|
|
49
53
|
if (app === platformaticRuntime || !app) {
|
|
50
|
-
return buildServerRuntime(options)
|
|
54
|
+
return buildServerRuntime(options, args)
|
|
51
55
|
}
|
|
52
56
|
|
|
53
57
|
if (app.buildServer) {
|
package/lib/runtime.js
CHANGED
|
@@ -9,7 +9,10 @@ const { setTimeout: sleep } = require('node:timers/promises')
|
|
|
9
9
|
const { Worker } = require('node:worker_threads')
|
|
10
10
|
|
|
11
11
|
const { ITC } = require('@platformatic/itc')
|
|
12
|
-
const {
|
|
12
|
+
const {
|
|
13
|
+
errors: { ensureLoggableError },
|
|
14
|
+
executeWithTimeout
|
|
15
|
+
} = require('@platformatic/utils')
|
|
13
16
|
const ts = require('tail-file-stream')
|
|
14
17
|
const { createThreadInterceptor } = require('undici-thread-interceptor')
|
|
15
18
|
|
|
@@ -64,7 +67,7 @@ class Runtime extends EventEmitter {
|
|
|
64
67
|
this.#servicesIds = []
|
|
65
68
|
this.#url = undefined
|
|
66
69
|
// Note: nothing hits the main thread so there is no reason to set the globalDispatcher here
|
|
67
|
-
this.#interceptor = createThreadInterceptor({ domain: '.plt.local' })
|
|
70
|
+
this.#interceptor = createThreadInterceptor({ domain: '.plt.local', timeout: true })
|
|
68
71
|
this.#status = undefined
|
|
69
72
|
this.#startedServices = new Map()
|
|
70
73
|
this.#restartPromises = new Map()
|
|
@@ -148,6 +151,7 @@ class Runtime extends EventEmitter {
|
|
|
148
151
|
this.startCollectingMetrics()
|
|
149
152
|
}
|
|
150
153
|
|
|
154
|
+
this.logger.info(`Platformatic is now listening at ${this.#url}`)
|
|
151
155
|
return this.#url
|
|
152
156
|
}
|
|
153
157
|
|
|
@@ -172,6 +176,7 @@ class Runtime extends EventEmitter {
|
|
|
172
176
|
|
|
173
177
|
this.emit('restarted')
|
|
174
178
|
|
|
179
|
+
this.logger.info(`Platformatic is now listening at ${this.#url}`)
|
|
175
180
|
return this.#url
|
|
176
181
|
}
|
|
177
182
|
|
|
@@ -236,7 +241,7 @@ class Runtime extends EventEmitter {
|
|
|
236
241
|
// TODO: handle port allocation error here
|
|
237
242
|
if (error.code === 'EADDRINUSE') throw error
|
|
238
243
|
|
|
239
|
-
this.logger.error({ error }, `Failed to start service "${id}".`)
|
|
244
|
+
this.logger.error({ error: ensureLoggableError(error) }, `Failed to start service "${id}".`)
|
|
240
245
|
|
|
241
246
|
const config = this.#configManager.current
|
|
242
247
|
const restartOnError = config.restartOnError
|
|
@@ -278,13 +283,18 @@ class Runtime extends EventEmitter {
|
|
|
278
283
|
|
|
279
284
|
// Always send the stop message, it will shut down workers that only had ITC and interceptors setup
|
|
280
285
|
try {
|
|
281
|
-
await
|
|
286
|
+
await executeWithTimeout(sendViaITC(service, 'stop'), 10000)
|
|
282
287
|
} catch (error) {
|
|
283
|
-
this.logger?.info(
|
|
288
|
+
this.logger?.info(
|
|
289
|
+
{ error: ensureLoggableError(error) },
|
|
290
|
+
`Failed to stop service "${id}". Killing a worker thread.`
|
|
291
|
+
)
|
|
292
|
+
} finally {
|
|
293
|
+
service[kITC].close()
|
|
284
294
|
}
|
|
285
295
|
|
|
286
296
|
// Wait for the worker thread to finish, we're going to create a new one if the service is ever restarted
|
|
287
|
-
const res = await
|
|
297
|
+
const res = await executeWithTimeout(once(service, 'exit'), 10000)
|
|
288
298
|
|
|
289
299
|
// If the worker didn't exit in time, kill it
|
|
290
300
|
if (res === 'timeout') {
|
|
@@ -292,6 +302,25 @@ class Runtime extends EventEmitter {
|
|
|
292
302
|
}
|
|
293
303
|
}
|
|
294
304
|
|
|
305
|
+
async buildService (id) {
|
|
306
|
+
const service = this.#services.get(id)
|
|
307
|
+
|
|
308
|
+
if (!service) {
|
|
309
|
+
throw new errors.ServiceNotFoundError(id, Array.from(this.#services.keys()).join(', '))
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
try {
|
|
313
|
+
return await sendViaITC(service, 'build')
|
|
314
|
+
} catch (e) {
|
|
315
|
+
// The service exports no meta, return an empty object
|
|
316
|
+
if (e.code === 'PLT_ITC_HANDLER_NOT_FOUND') {
|
|
317
|
+
return {}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
throw e
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
295
324
|
async inject (id, injectParams) {
|
|
296
325
|
const service = await this.#getServiceById(id, true)
|
|
297
326
|
return sendViaITC(service, 'inject', injectParams)
|
|
@@ -577,9 +606,7 @@ class Runtime extends EventEmitter {
|
|
|
577
606
|
let p99Value = 0
|
|
578
607
|
|
|
579
608
|
const metricName = 'http_request_all_summary_seconds'
|
|
580
|
-
const httpLatencyMetrics = metrics.filter(
|
|
581
|
-
metric => metric.name === metricName
|
|
582
|
-
)
|
|
609
|
+
const httpLatencyMetrics = metrics.filter(metric => metric.name === metricName)
|
|
583
610
|
|
|
584
611
|
if (httpLatencyMetrics) {
|
|
585
612
|
const entrypointMetrics = httpLatencyMetrics.find(
|
|
@@ -635,6 +662,25 @@ class Runtime extends EventEmitter {
|
|
|
635
662
|
}
|
|
636
663
|
}
|
|
637
664
|
|
|
665
|
+
async getServiceMeta (id) {
|
|
666
|
+
const service = this.#services.get(id)
|
|
667
|
+
|
|
668
|
+
if (!service) {
|
|
669
|
+
throw new errors.ServiceNotFoundError(id, Array.from(this.#services.keys()).join(', '))
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
try {
|
|
673
|
+
return await sendViaITC(service, 'getServiceMeta')
|
|
674
|
+
} catch (e) {
|
|
675
|
+
// The service exports no meta, return an empty object
|
|
676
|
+
if (e.code === 'PLT_ITC_HANDLER_NOT_FOUND') {
|
|
677
|
+
return {}
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
throw e
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
|
|
638
684
|
async getLogIds (runtimePID) {
|
|
639
685
|
runtimePID = runtimePID ?? process.pid
|
|
640
686
|
|
|
@@ -695,7 +741,10 @@ class Runtime extends EventEmitter {
|
|
|
695
741
|
const service = new Worker(kWorkerFile, {
|
|
696
742
|
workerData: {
|
|
697
743
|
config,
|
|
698
|
-
serviceConfig
|
|
744
|
+
serviceConfig: {
|
|
745
|
+
...serviceConfig,
|
|
746
|
+
isProduction: this.#configManager.args?.production ?? false
|
|
747
|
+
},
|
|
699
748
|
dirname: this.#configManager.dirname,
|
|
700
749
|
runtimeLogsDir: this.#runtimeLogsDir,
|
|
701
750
|
loggingPort
|
|
@@ -722,6 +771,7 @@ class Runtime extends EventEmitter {
|
|
|
722
771
|
const started = this.#startedServices.get(id)
|
|
723
772
|
this.#services.delete(id)
|
|
724
773
|
loggerDestination.close()
|
|
774
|
+
service[kITC].close()
|
|
725
775
|
loggingPort.close()
|
|
726
776
|
|
|
727
777
|
if (this.#status === 'stopping') return
|
|
@@ -735,7 +785,7 @@ class Runtime extends EventEmitter {
|
|
|
735
785
|
if (restartOnError > 0) {
|
|
736
786
|
this.logger.warn(`Restarting a service "${id}" in ${restartOnError}ms...`)
|
|
737
787
|
this.#restartCrashedService(id).catch(err => {
|
|
738
|
-
this.logger.error({ err }, `Failed to restart service "${id}".`)
|
|
788
|
+
this.logger.error({ err: ensureLoggableError(err) }, `Failed to restart service "${id}".`)
|
|
739
789
|
})
|
|
740
790
|
} else {
|
|
741
791
|
this.logger.warn(`The "${id}" service is no longer available.`)
|
|
@@ -749,6 +799,7 @@ class Runtime extends EventEmitter {
|
|
|
749
799
|
|
|
750
800
|
// Setup ITC
|
|
751
801
|
service[kITC] = new ITC({
|
|
802
|
+
name: id + '-runtime',
|
|
752
803
|
port: service,
|
|
753
804
|
handlers: {
|
|
754
805
|
getServiceMeta: this.getServiceMeta.bind(this)
|
|
@@ -856,25 +907,6 @@ class Runtime extends EventEmitter {
|
|
|
856
907
|
return service
|
|
857
908
|
}
|
|
858
909
|
|
|
859
|
-
async getServiceMeta (id) {
|
|
860
|
-
const service = this.#services.get(id)
|
|
861
|
-
|
|
862
|
-
if (!service) {
|
|
863
|
-
throw new errors.ServiceNotFoundError(id, Array.from(this.#services.keys()).join(', '))
|
|
864
|
-
}
|
|
865
|
-
|
|
866
|
-
try {
|
|
867
|
-
return await service[kITC].send('getServiceMeta')
|
|
868
|
-
} catch (e) {
|
|
869
|
-
// The service exports no meta, return an empty object
|
|
870
|
-
if (e.code === 'PLT_ITC_HANDLER_NOT_FOUND') {
|
|
871
|
-
return {}
|
|
872
|
-
}
|
|
873
|
-
|
|
874
|
-
throw e
|
|
875
|
-
}
|
|
876
|
-
}
|
|
877
|
-
|
|
878
910
|
async #getRuntimePackageJson () {
|
|
879
911
|
const runtimeDir = this.#configManager.dirname
|
|
880
912
|
const packageJsonPath = join(runtimeDir, 'package.json')
|
|
@@ -903,7 +935,7 @@ class Runtime extends EventEmitter {
|
|
|
903
935
|
try {
|
|
904
936
|
await access(this.#runtimeTmpDir)
|
|
905
937
|
} catch (err) {
|
|
906
|
-
this.logger.error({ err }, 'Cannot access temporary folder.')
|
|
938
|
+
this.logger.error({ err: ensureLoggableError(err) }, 'Cannot access temporary folder.')
|
|
907
939
|
return []
|
|
908
940
|
}
|
|
909
941
|
|
package/lib/schema.js
CHANGED
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
'use strict'
|
|
3
3
|
|
|
4
4
|
const telemetry = require('@platformatic/telemetry').schema
|
|
5
|
-
const {
|
|
5
|
+
const {
|
|
6
|
+
schemaComponents: { server }
|
|
7
|
+
} = require('@platformatic/utils')
|
|
6
8
|
|
|
7
9
|
const pkg = require('../package.json')
|
|
8
10
|
const platformaticRuntimeSchema = {
|
|
@@ -11,11 +13,11 @@ const platformaticRuntimeSchema = {
|
|
|
11
13
|
type: 'object',
|
|
12
14
|
properties: {
|
|
13
15
|
$schema: {
|
|
14
|
-
type: 'string'
|
|
16
|
+
type: 'string'
|
|
15
17
|
},
|
|
16
18
|
preload: {
|
|
17
19
|
type: 'string',
|
|
18
|
-
resolvePath: true
|
|
20
|
+
resolvePath: true
|
|
19
21
|
},
|
|
20
22
|
autoload: {
|
|
21
23
|
type: 'object',
|
|
@@ -24,14 +26,14 @@ const platformaticRuntimeSchema = {
|
|
|
24
26
|
properties: {
|
|
25
27
|
path: {
|
|
26
28
|
type: 'string',
|
|
27
|
-
resolvePath: true
|
|
29
|
+
resolvePath: true
|
|
28
30
|
},
|
|
29
31
|
exclude: {
|
|
30
32
|
type: 'array',
|
|
31
33
|
default: [],
|
|
32
34
|
items: {
|
|
33
|
-
type: 'string'
|
|
34
|
-
}
|
|
35
|
+
type: 'string'
|
|
36
|
+
}
|
|
35
37
|
},
|
|
36
38
|
mappings: {
|
|
37
39
|
type: 'object',
|
|
@@ -41,89 +43,92 @@ const platformaticRuntimeSchema = {
|
|
|
41
43
|
required: ['id'],
|
|
42
44
|
properties: {
|
|
43
45
|
id: {
|
|
44
|
-
type: 'string'
|
|
46
|
+
type: 'string'
|
|
45
47
|
},
|
|
46
48
|
config: {
|
|
47
|
-
type: 'string'
|
|
49
|
+
type: 'string'
|
|
48
50
|
},
|
|
49
51
|
useHttp: {
|
|
50
|
-
type: 'boolean'
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
}
|
|
52
|
+
type: 'boolean'
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
56
58
|
},
|
|
57
59
|
telemetry,
|
|
58
60
|
server,
|
|
59
61
|
entrypoint: {
|
|
60
|
-
type: 'string'
|
|
62
|
+
type: 'string'
|
|
61
63
|
},
|
|
62
64
|
watch: {
|
|
63
65
|
anyOf: [
|
|
64
66
|
{
|
|
65
|
-
type: 'boolean'
|
|
67
|
+
type: 'boolean'
|
|
66
68
|
},
|
|
67
69
|
{
|
|
68
|
-
type: 'string'
|
|
69
|
-
}
|
|
70
|
-
]
|
|
70
|
+
type: 'string'
|
|
71
|
+
}
|
|
72
|
+
]
|
|
71
73
|
},
|
|
72
74
|
inspectorOptions: {
|
|
73
75
|
type: 'object',
|
|
74
76
|
properties: {
|
|
75
77
|
host: {
|
|
76
|
-
type: 'string'
|
|
78
|
+
type: 'string'
|
|
77
79
|
},
|
|
78
80
|
port: {
|
|
79
|
-
type: 'number'
|
|
81
|
+
type: 'number'
|
|
80
82
|
},
|
|
81
83
|
breakFirstLine: {
|
|
82
|
-
type: 'boolean'
|
|
84
|
+
type: 'boolean'
|
|
83
85
|
},
|
|
84
86
|
watchDisabled: {
|
|
85
|
-
type: 'boolean'
|
|
86
|
-
}
|
|
87
|
-
}
|
|
87
|
+
type: 'boolean'
|
|
88
|
+
}
|
|
89
|
+
}
|
|
88
90
|
},
|
|
89
91
|
undici: {
|
|
90
92
|
type: 'object',
|
|
91
93
|
properties: {
|
|
92
94
|
agentOptions: {
|
|
93
95
|
type: 'object',
|
|
94
|
-
additionalProperties: true
|
|
96
|
+
additionalProperties: true
|
|
95
97
|
},
|
|
96
98
|
interceptors: {
|
|
97
|
-
anyOf: [
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
99
|
+
anyOf: [
|
|
100
|
+
{
|
|
101
|
+
type: 'array',
|
|
102
|
+
items: {
|
|
103
|
+
$ref: '#/$defs/undiciInterceptor'
|
|
104
|
+
}
|
|
101
105
|
},
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
},
|
|
111
|
-
Pool: {
|
|
112
|
-
type: 'array',
|
|
113
|
-
items: {
|
|
114
|
-
$ref: '#/$defs/undiciInterceptor',
|
|
106
|
+
{
|
|
107
|
+
type: 'object',
|
|
108
|
+
properties: {
|
|
109
|
+
Client: {
|
|
110
|
+
type: 'array',
|
|
111
|
+
items: {
|
|
112
|
+
$ref: '#/$defs/undiciInterceptor'
|
|
113
|
+
}
|
|
115
114
|
},
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
115
|
+
Pool: {
|
|
116
|
+
type: 'array',
|
|
117
|
+
items: {
|
|
118
|
+
$ref: '#/$defs/undiciInterceptor'
|
|
119
|
+
}
|
|
121
120
|
},
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
121
|
+
Agent: {
|
|
122
|
+
type: 'array',
|
|
123
|
+
items: {
|
|
124
|
+
$ref: '#/$defs/undiciInterceptor'
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
]
|
|
130
|
+
}
|
|
131
|
+
}
|
|
127
132
|
},
|
|
128
133
|
managementApi: {
|
|
129
134
|
anyOf: [
|
|
@@ -136,14 +141,14 @@ const platformaticRuntimeSchema = {
|
|
|
136
141
|
maxSize: {
|
|
137
142
|
type: 'number',
|
|
138
143
|
minimum: 5,
|
|
139
|
-
default: 200
|
|
140
|
-
}
|
|
141
|
-
}
|
|
144
|
+
default: 200
|
|
145
|
+
}
|
|
146
|
+
}
|
|
142
147
|
},
|
|
143
|
-
additionalProperties: false
|
|
144
|
-
}
|
|
148
|
+
additionalProperties: false
|
|
149
|
+
}
|
|
145
150
|
],
|
|
146
|
-
default: true
|
|
151
|
+
default: true
|
|
147
152
|
},
|
|
148
153
|
metrics: {
|
|
149
154
|
anyOf: [
|
|
@@ -152,10 +157,7 @@ const platformaticRuntimeSchema = {
|
|
|
152
157
|
type: 'object',
|
|
153
158
|
properties: {
|
|
154
159
|
port: {
|
|
155
|
-
anyOf: [
|
|
156
|
-
{ type: 'integer' },
|
|
157
|
-
{ type: 'string' },
|
|
158
|
-
],
|
|
160
|
+
anyOf: [{ type: 'integer' }, { type: 'string' }]
|
|
159
161
|
},
|
|
160
162
|
hostname: { type: 'string' },
|
|
161
163
|
endpoint: { type: 'string' },
|
|
@@ -163,19 +165,19 @@ const platformaticRuntimeSchema = {
|
|
|
163
165
|
type: 'object',
|
|
164
166
|
properties: {
|
|
165
167
|
username: { type: 'string' },
|
|
166
|
-
password: { type: 'string' }
|
|
168
|
+
password: { type: 'string' }
|
|
167
169
|
},
|
|
168
170
|
additionalProperties: false,
|
|
169
|
-
required: ['username', 'password']
|
|
171
|
+
required: ['username', 'password']
|
|
170
172
|
},
|
|
171
173
|
labels: {
|
|
172
174
|
type: 'object',
|
|
173
|
-
additionalProperties: { type: 'string' }
|
|
174
|
-
}
|
|
175
|
+
additionalProperties: { type: 'string' }
|
|
176
|
+
}
|
|
175
177
|
},
|
|
176
|
-
additionalProperties: false
|
|
177
|
-
}
|
|
178
|
-
]
|
|
178
|
+
additionalProperties: false
|
|
179
|
+
}
|
|
180
|
+
]
|
|
179
181
|
},
|
|
180
182
|
restartOnError: {
|
|
181
183
|
default: true,
|
|
@@ -183,59 +185,53 @@ const platformaticRuntimeSchema = {
|
|
|
183
185
|
{ type: 'boolean' },
|
|
184
186
|
{
|
|
185
187
|
type: 'number',
|
|
186
|
-
minimum: 100
|
|
187
|
-
}
|
|
188
|
-
]
|
|
188
|
+
minimum: 100
|
|
189
|
+
}
|
|
190
|
+
]
|
|
189
191
|
},
|
|
190
192
|
services: {
|
|
191
193
|
type: 'array',
|
|
192
194
|
items: {
|
|
193
195
|
type: 'object',
|
|
194
|
-
anyOf: [
|
|
195
|
-
{ required: ['id', 'path'] },
|
|
196
|
-
{ required: ['id', 'url'] },
|
|
197
|
-
],
|
|
196
|
+
anyOf: [{ required: ['id', 'path'] }, { required: ['id', 'url'] }],
|
|
198
197
|
properties: {
|
|
199
198
|
id: {
|
|
200
|
-
type: 'string'
|
|
199
|
+
type: 'string'
|
|
201
200
|
},
|
|
202
201
|
path: {
|
|
203
202
|
type: 'string',
|
|
204
|
-
resolvePath: true
|
|
203
|
+
resolvePath: true
|
|
205
204
|
},
|
|
206
205
|
config: {
|
|
207
|
-
type: 'string'
|
|
206
|
+
type: 'string'
|
|
208
207
|
},
|
|
209
208
|
url: {
|
|
210
|
-
type: 'string'
|
|
209
|
+
type: 'string'
|
|
211
210
|
},
|
|
212
211
|
useHttp: {
|
|
213
|
-
type: 'boolean'
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
}
|
|
212
|
+
type: 'boolean'
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
218
217
|
},
|
|
219
|
-
anyOf: [
|
|
220
|
-
{ required: ['autoload', 'entrypoint'] },
|
|
221
|
-
{ required: ['services', 'entrypoint'] },
|
|
222
|
-
],
|
|
218
|
+
anyOf: [{ required: ['autoload', 'entrypoint'] }, { required: ['services', 'entrypoint'] }],
|
|
223
219
|
additionalProperties: false,
|
|
224
220
|
$defs: {
|
|
225
221
|
undiciInterceptor: {
|
|
226
222
|
type: 'object',
|
|
227
223
|
properties: {
|
|
228
224
|
module: {
|
|
229
|
-
type: 'string'
|
|
225
|
+
type: 'string'
|
|
230
226
|
},
|
|
231
227
|
options: {
|
|
232
228
|
type: 'object',
|
|
233
|
-
additionalProperties: true
|
|
234
|
-
}
|
|
229
|
+
additionalProperties: true
|
|
230
|
+
}
|
|
235
231
|
},
|
|
236
|
-
required: ['module', 'options']
|
|
237
|
-
}
|
|
238
|
-
}
|
|
232
|
+
required: ['module', 'options']
|
|
233
|
+
}
|
|
234
|
+
}
|
|
239
235
|
}
|
|
240
236
|
|
|
241
237
|
module.exports.schema = platformaticRuntimeSchema
|
package/lib/start.js
CHANGED
|
@@ -5,6 +5,9 @@ const { writeFile } = require('node:fs/promises')
|
|
|
5
5
|
const { join, resolve, dirname } = require('node:path')
|
|
6
6
|
|
|
7
7
|
const { printConfigValidationErrors } = require('@platformatic/config')
|
|
8
|
+
const {
|
|
9
|
+
errors: { ensureLoggableError }
|
|
10
|
+
} = require('@platformatic/utils')
|
|
8
11
|
const closeWithGrace = require('close-with-grace')
|
|
9
12
|
const pino = require('pino')
|
|
10
13
|
const pretty = require('pino-pretty')
|
|
@@ -38,7 +41,7 @@ async function buildRuntime (configManager, env) {
|
|
|
38
41
|
try {
|
|
39
42
|
await runtime.restart()
|
|
40
43
|
} catch (err) {
|
|
41
|
-
runtime.logger.error({ err }, 'Failed to restart services.')
|
|
44
|
+
runtime.logger.error({ err: ensureLoggableError(err) }, 'Failed to restart services.')
|
|
42
45
|
}
|
|
43
46
|
})
|
|
44
47
|
|
|
@@ -96,7 +99,7 @@ async function setupAndStartRuntime (config) {
|
|
|
96
99
|
const logger = pino(
|
|
97
100
|
pretty({
|
|
98
101
|
translateTime: 'SYS:HH:MM:ss',
|
|
99
|
-
ignore: 'hostname,pid'
|
|
102
|
+
ignore: 'hostname,pid'
|
|
100
103
|
})
|
|
101
104
|
)
|
|
102
105
|
logger.warn(`Port: ${originalPort} is already in use!`)
|
|
@@ -107,7 +110,15 @@ async function setupAndStartRuntime (config) {
|
|
|
107
110
|
|
|
108
111
|
async function startCommand (args) {
|
|
109
112
|
try {
|
|
110
|
-
const config = await loadConfig(
|
|
113
|
+
const config = await loadConfig(
|
|
114
|
+
{
|
|
115
|
+
alias: {
|
|
116
|
+
p: 'production'
|
|
117
|
+
},
|
|
118
|
+
boolean: ['p', 'production']
|
|
119
|
+
},
|
|
120
|
+
args
|
|
121
|
+
)
|
|
111
122
|
|
|
112
123
|
const startResult = await setupAndStartRuntime(config)
|
|
113
124
|
|
|
@@ -130,16 +141,16 @@ async function startCommand (args) {
|
|
|
130
141
|
hostname: '127.0.0.1',
|
|
131
142
|
port: 3042,
|
|
132
143
|
logger: {
|
|
133
|
-
level: 'info'
|
|
134
|
-
}
|
|
144
|
+
level: 'info'
|
|
145
|
+
}
|
|
135
146
|
},
|
|
136
147
|
plugins: {
|
|
137
|
-
paths: [args[0]]
|
|
148
|
+
paths: [args[0]]
|
|
138
149
|
},
|
|
139
150
|
service: {
|
|
140
|
-
openapi: true
|
|
151
|
+
openapi: true
|
|
141
152
|
},
|
|
142
|
-
watch: true
|
|
153
|
+
watch: true
|
|
143
154
|
}
|
|
144
155
|
const toWrite = join(dirname(resolve(args[0])), 'platformatic.service.json')
|
|
145
156
|
console.log(`No config file found, creating ${join(dirname(args[0]), 'platformatic.service.json')}`)
|
package/lib/worker/app.js
CHANGED
|
@@ -35,12 +35,12 @@ class PlatformaticApp extends EventEmitter {
|
|
|
35
35
|
serviceId: this.appConfig.id,
|
|
36
36
|
directory: this.appConfig.path,
|
|
37
37
|
isEntrypoint: this.appConfig.entrypoint,
|
|
38
|
-
isProduction:
|
|
38
|
+
isProduction: this.appConfig.isProduction,
|
|
39
39
|
telemetryConfig,
|
|
40
40
|
metricsConfig,
|
|
41
41
|
serverConfig,
|
|
42
42
|
hasManagementApi: !!hasManagementApi,
|
|
43
|
-
localServiceEnvVars: this.appConfig.localServiceEnvVars
|
|
43
|
+
localServiceEnvVars: this.appConfig.localServiceEnvVars
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
46
|
|
|
@@ -71,7 +71,7 @@ class PlatformaticApp extends EventEmitter {
|
|
|
71
71
|
appConfig.path,
|
|
72
72
|
{
|
|
73
73
|
onMissingEnv: this.#fetchServiceUrl,
|
|
74
|
-
context: appConfig
|
|
74
|
+
context: appConfig
|
|
75
75
|
},
|
|
76
76
|
true
|
|
77
77
|
)
|
|
@@ -81,7 +81,7 @@ class PlatformaticApp extends EventEmitter {
|
|
|
81
81
|
['-c', appConfig.config],
|
|
82
82
|
{
|
|
83
83
|
onMissingEnv: this.#fetchServiceUrl,
|
|
84
|
-
context: appConfig
|
|
84
|
+
context: appConfig
|
|
85
85
|
},
|
|
86
86
|
true
|
|
87
87
|
)
|
|
@@ -89,10 +89,14 @@ class PlatformaticApp extends EventEmitter {
|
|
|
89
89
|
|
|
90
90
|
const app = loadedConfig.app
|
|
91
91
|
|
|
92
|
+
if (appConfig.isProduction && !process.env.NODE_ENV) {
|
|
93
|
+
process.env.NODE_ENV = 'production'
|
|
94
|
+
}
|
|
95
|
+
|
|
92
96
|
const stackable = await app.buildStackable({
|
|
93
97
|
onMissingEnv: this.#fetchServiceUrl,
|
|
94
98
|
config: this.appConfig.config,
|
|
95
|
-
context: this.#context
|
|
99
|
+
context: this.#context
|
|
96
100
|
})
|
|
97
101
|
this.stackable = this.#wrapStackable(stackable)
|
|
98
102
|
|
|
@@ -203,7 +207,7 @@ class PlatformaticApp extends EventEmitter {
|
|
|
203
207
|
path: watch.path,
|
|
204
208
|
/* c8 ignore next 2 */
|
|
205
209
|
allowToWatch: watch?.allow,
|
|
206
|
-
watchIgnore: watch?.ignore || []
|
|
210
|
+
watchIgnore: watch?.ignore || []
|
|
207
211
|
})
|
|
208
212
|
|
|
209
213
|
fileWatcher.on('update', this.#debouncedRestart)
|
|
@@ -246,7 +250,7 @@ class PlatformaticApp extends EventEmitter {
|
|
|
246
250
|
if (telemetryId) {
|
|
247
251
|
opts.headers = {
|
|
248
252
|
...opts.headers,
|
|
249
|
-
'x-plt-telemetry-id': telemetryId
|
|
253
|
+
'x-plt-telemetry-id': telemetryId
|
|
250
254
|
}
|
|
251
255
|
}
|
|
252
256
|
return dispatch(opts, handler)
|
package/lib/worker/itc.js
CHANGED
|
@@ -44,6 +44,7 @@ async function sendViaITC (worker, name, message) {
|
|
|
44
44
|
|
|
45
45
|
function setupITC (app, service, dispatcher) {
|
|
46
46
|
const itc = new ITC({
|
|
47
|
+
name: app.appConfig.id + '-worker',
|
|
47
48
|
port: parentPort,
|
|
48
49
|
handlers: {
|
|
49
50
|
async start () {
|
|
@@ -82,6 +83,10 @@ function setupITC (app, service, dispatcher) {
|
|
|
82
83
|
itc.close()
|
|
83
84
|
},
|
|
84
85
|
|
|
86
|
+
async build () {
|
|
87
|
+
return app.stackable.build()
|
|
88
|
+
},
|
|
89
|
+
|
|
85
90
|
getStatus () {
|
|
86
91
|
return app.getStatus()
|
|
87
92
|
},
|
package/lib/worker/main.js
CHANGED
|
@@ -2,11 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
const { createRequire } = require('node:module')
|
|
4
4
|
const { join } = require('node:path')
|
|
5
|
-
const { setTimeout: sleep } = require('node:timers/promises')
|
|
6
5
|
const { parentPort, workerData, threadId } = require('node:worker_threads')
|
|
7
6
|
const { pathToFileURL } = require('node:url')
|
|
8
7
|
|
|
9
|
-
const { Unpromise } = require('@watchable/unpromise')
|
|
10
8
|
const pino = require('pino')
|
|
11
9
|
const { fetch, setGlobalDispatcher, Agent } = require('undici')
|
|
12
10
|
const { wire } = require('undici-thread-interceptor')
|
|
@@ -14,7 +12,7 @@ const { wire } = require('undici-thread-interceptor')
|
|
|
14
12
|
const { PlatformaticApp } = require('./app')
|
|
15
13
|
const { setupITC } = require('./itc')
|
|
16
14
|
const loadInterceptors = require('./interceptors')
|
|
17
|
-
const { MessagePortWritable, createPinoWritable } = require('@platformatic/utils')
|
|
15
|
+
const { MessagePortWritable, createPinoWritable, executeWithTimeout, errors } = require('@platformatic/utils')
|
|
18
16
|
const { kId, kITC } = require('./symbols')
|
|
19
17
|
|
|
20
18
|
process.on('uncaughtException', handleUnhandled.bind(null, 'uncaught exception'))
|
|
@@ -25,12 +23,15 @@ globalThis[kId] = threadId
|
|
|
25
23
|
|
|
26
24
|
let app
|
|
27
25
|
const config = workerData.config
|
|
28
|
-
|
|
26
|
+
globalThis.platformatic = Object.assign(globalThis.platformatic ?? {}, { logger: createLogger() })
|
|
29
27
|
|
|
30
28
|
function handleUnhandled (type, err) {
|
|
31
|
-
logger.error(
|
|
29
|
+
globalThis.platformatic.logger.error(
|
|
30
|
+
{ err: errors.ensureLoggableError(err) },
|
|
31
|
+
`Service ${workerData.serviceConfig.id} threw an ${type}.`
|
|
32
|
+
)
|
|
32
33
|
|
|
33
|
-
|
|
34
|
+
executeWithTimeout(app?.stop(), 1000)
|
|
34
35
|
.catch()
|
|
35
36
|
.finally(() => {
|
|
36
37
|
process.exit(1)
|
|
@@ -73,13 +74,13 @@ async function main () {
|
|
|
73
74
|
|
|
74
75
|
const globalDispatcher = new Agent({
|
|
75
76
|
...config.undici,
|
|
76
|
-
interceptors
|
|
77
|
+
interceptors
|
|
77
78
|
}).compose(composedInterceptors)
|
|
78
79
|
|
|
79
80
|
setGlobalDispatcher(globalDispatcher)
|
|
80
81
|
|
|
81
82
|
// Setup mesh networker
|
|
82
|
-
const threadDispatcher = wire({ port: parentPort, useNetwork: service.useHttp })
|
|
83
|
+
const threadDispatcher = wire({ port: parentPort, useNetwork: service.useHttp, timeout: true })
|
|
83
84
|
|
|
84
85
|
// If the service is an entrypoint and runtime server config is defined, use it.
|
|
85
86
|
let serverConfig = null
|
|
@@ -89,7 +90,7 @@ async function main () {
|
|
|
89
90
|
serverConfig = {
|
|
90
91
|
port: 0,
|
|
91
92
|
hostname: '127.0.0.1',
|
|
92
|
-
keepAliveTimeout: 5000
|
|
93
|
+
keepAliveTimeout: 5000
|
|
93
94
|
}
|
|
94
95
|
}
|
|
95
96
|
|
|
@@ -97,7 +98,7 @@ async function main () {
|
|
|
97
98
|
if (telemetryConfig) {
|
|
98
99
|
telemetryConfig = {
|
|
99
100
|
...telemetryConfig,
|
|
100
|
-
serviceName: `${telemetryConfig.serviceName}-${service.id}
|
|
101
|
+
serviceName: `${telemetryConfig.serviceName}-${service.id}`
|
|
101
102
|
}
|
|
102
103
|
}
|
|
103
104
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@platformatic/runtime",
|
|
3
|
-
"version": "2.0.0-alpha.
|
|
3
|
+
"version": "2.0.0-alpha.9",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -17,8 +17,8 @@
|
|
|
17
17
|
},
|
|
18
18
|
"homepage": "https://github.com/platformatic/platformatic#readme",
|
|
19
19
|
"devDependencies": {
|
|
20
|
-
"@fastify/express": "^
|
|
21
|
-
"@fastify/formbody": "^
|
|
20
|
+
"@fastify/express": "^4.0.0",
|
|
21
|
+
"@fastify/formbody": "^8.0.0",
|
|
22
22
|
"borp": "^0.17.0",
|
|
23
23
|
"c8": "^10.0.0",
|
|
24
24
|
"eslint": "9",
|
|
@@ -34,14 +34,14 @@
|
|
|
34
34
|
"typescript": "^5.5.4",
|
|
35
35
|
"undici-oidc-interceptor": "^0.5.0",
|
|
36
36
|
"why-is-node-running": "^2.2.2",
|
|
37
|
-
"@platformatic/composer": "2.0.0-alpha.
|
|
38
|
-
"@platformatic/
|
|
39
|
-
"@platformatic/
|
|
40
|
-
"@platformatic/sql-graphql": "2.0.0-alpha.
|
|
41
|
-
"@platformatic/sql-mapper": "2.0.0-alpha.
|
|
37
|
+
"@platformatic/composer": "2.0.0-alpha.9",
|
|
38
|
+
"@platformatic/service": "2.0.0-alpha.9",
|
|
39
|
+
"@platformatic/db": "2.0.0-alpha.9",
|
|
40
|
+
"@platformatic/sql-graphql": "2.0.0-alpha.9",
|
|
41
|
+
"@platformatic/sql-mapper": "2.0.0-alpha.9"
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"@fastify/error": "^
|
|
44
|
+
"@fastify/error": "^4.0.0",
|
|
45
45
|
"@fastify/websocket": "^10.0.0",
|
|
46
46
|
"@hapi/topo": "^6.0.2",
|
|
47
47
|
"@platformatic/http-metrics": "^0.1.0",
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"dotenv-tool": "^0.1.1",
|
|
56
56
|
"es-main": "^1.3.0",
|
|
57
57
|
"fastest-levenshtein": "^1.0.16",
|
|
58
|
-
"fastify": "
|
|
58
|
+
"fastify": "5.0.0-alpha.4",
|
|
59
59
|
"fastify-undici-dispatcher": "^0.6.0",
|
|
60
60
|
"graphql": "^16.8.1",
|
|
61
61
|
"help-me": "^5.0.0",
|
|
@@ -67,15 +67,15 @@
|
|
|
67
67
|
"semgrator": "^0.3.0",
|
|
68
68
|
"tail-file-stream": "^0.2.0",
|
|
69
69
|
"undici": "^6.9.0",
|
|
70
|
-
"undici-thread-interceptor": "^0.
|
|
70
|
+
"undici-thread-interceptor": "^0.6.1",
|
|
71
71
|
"ws": "^8.16.0",
|
|
72
|
-
"@platformatic/basic": "2.0.0-alpha.
|
|
73
|
-
"@platformatic/config": "2.0.0-alpha.
|
|
74
|
-
"@platformatic/generators": "2.0.0-alpha.
|
|
75
|
-
"@platformatic/itc": "2.0.0-alpha.
|
|
76
|
-
"@platformatic/telemetry": "2.0.0-alpha.
|
|
77
|
-
"@platformatic/
|
|
78
|
-
"@platformatic/
|
|
72
|
+
"@platformatic/basic": "2.0.0-alpha.9",
|
|
73
|
+
"@platformatic/config": "2.0.0-alpha.9",
|
|
74
|
+
"@platformatic/generators": "2.0.0-alpha.9",
|
|
75
|
+
"@platformatic/itc": "2.0.0-alpha.9",
|
|
76
|
+
"@platformatic/telemetry": "2.0.0-alpha.9",
|
|
77
|
+
"@platformatic/utils": "2.0.0-alpha.9",
|
|
78
|
+
"@platformatic/ts-compiler": "2.0.0-alpha.9"
|
|
79
79
|
},
|
|
80
80
|
"scripts": {
|
|
81
81
|
"test": "npm run lint && borp --concurrency=1 --timeout=180000 && tsd",
|
package/schema.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"$id": "https://schemas.platformatic.dev/@platformatic/runtime/2.0.0-alpha.
|
|
2
|
+
"$id": "https://schemas.platformatic.dev/@platformatic/runtime/2.0.0-alpha.9.json",
|
|
3
3
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
4
4
|
"type": "object",
|
|
5
5
|
"properties": {
|
|
@@ -316,6 +316,9 @@
|
|
|
316
316
|
}
|
|
317
317
|
]
|
|
318
318
|
},
|
|
319
|
+
"loggerInstance": {
|
|
320
|
+
"type": "object"
|
|
321
|
+
},
|
|
319
322
|
"serializerOpts": {
|
|
320
323
|
"type": "object",
|
|
321
324
|
"properties": {
|