@platformatic/runtime 2.22.0 → 2.24.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 +2 -1
- package/lib/build-server.js +1 -1
- package/lib/compile.js +26 -16
- package/lib/generator/runtime-generator.js +36 -38
- package/lib/runtime.js +108 -25
- package/lib/schema.js +17 -1
- package/lib/shared-http-cache.js +3 -3
- package/lib/worker/app.js +3 -5
- package/lib/worker/default-stackable.js +0 -1
- package/lib/worker/interceptors.js +6 -4
- package/lib/worker/main.js +9 -8
- package/lib/worker/round-robin-map.js +3 -1
- package/package.json +16 -17
- package/schema.json +37 -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 HttpsSchemasPlatformaticDevPlatformaticRuntime2240Json = {
|
|
9
9
|
[k: string]: unknown;
|
|
10
10
|
} & {
|
|
11
11
|
$schema?: string;
|
|
@@ -180,6 +180,7 @@ export type HttpsSchemasPlatformaticDevPlatformaticRuntime2220Json = {
|
|
|
180
180
|
env?: {
|
|
181
181
|
[k: string]: string;
|
|
182
182
|
};
|
|
183
|
+
sourceMaps?: boolean;
|
|
183
184
|
};
|
|
184
185
|
|
|
185
186
|
export interface UndiciInterceptor {
|
package/lib/build-server.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const { createRequire } = require('node:module')
|
|
4
3
|
const { join } = require('node:path')
|
|
5
4
|
|
|
6
5
|
const ConfigManager = require('@platformatic/config')
|
|
6
|
+
const { createRequire } = require('@platformatic/utils')
|
|
7
7
|
|
|
8
8
|
const { platformaticRuntime } = require('./config')
|
|
9
9
|
const { buildRuntime } = require('./start')
|
package/lib/compile.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const { createRequire } = require('
|
|
3
|
+
const { createRequire } = require('@platformatic/utils')
|
|
4
4
|
const { dirname, join } = require('node:path')
|
|
5
5
|
const { isatty } = require('node:tty')
|
|
6
6
|
const { pathToFileURL } = require('node:url')
|
|
@@ -12,9 +12,14 @@ const pretty = require('pino-pretty')
|
|
|
12
12
|
const { loadConfig } = require('./utils')
|
|
13
13
|
|
|
14
14
|
async function compile (argv, logger) {
|
|
15
|
-
const { configManager, configType, app } = await loadConfig(
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
const { configManager, configType, app } = await loadConfig(
|
|
16
|
+
{},
|
|
17
|
+
argv,
|
|
18
|
+
{
|
|
19
|
+
watch: false
|
|
20
|
+
},
|
|
21
|
+
false
|
|
22
|
+
)
|
|
18
23
|
/* c8 ignore next */
|
|
19
24
|
if (!logger) {
|
|
20
25
|
let stream
|
|
@@ -22,7 +27,7 @@ async function compile (argv, logger) {
|
|
|
22
27
|
if (isatty(process.stdout.fd)) {
|
|
23
28
|
stream = pretty({
|
|
24
29
|
translateTime: 'SYS:HH:MM:ss',
|
|
25
|
-
ignore: 'hostname,pid'
|
|
30
|
+
ignore: 'hostname,pid'
|
|
26
31
|
})
|
|
27
32
|
}
|
|
28
33
|
|
|
@@ -31,19 +36,24 @@ async function compile (argv, logger) {
|
|
|
31
36
|
|
|
32
37
|
let compiled = false
|
|
33
38
|
const compileOptions = {
|
|
34
|
-
clean: argv.includes('--clean')
|
|
39
|
+
clean: argv.includes('--clean')
|
|
35
40
|
}
|
|
36
41
|
if (configType === 'runtime') {
|
|
37
42
|
for (const service of configManager.current.services) {
|
|
38
43
|
const childLogger = logger.child({ name: service.id })
|
|
39
44
|
|
|
40
45
|
const serviceConfigPath = service.config
|
|
41
|
-
const { configManager, app } = await loadConfig(
|
|
42
|
-
|
|
43
|
-
|
|
46
|
+
const { configManager, app } = await loadConfig(
|
|
47
|
+
{},
|
|
48
|
+
['-c', serviceConfigPath],
|
|
49
|
+
{
|
|
50
|
+
onMissingEnv (key) {
|
|
51
|
+
return service.localServiceEnvVars.get(key)
|
|
52
|
+
},
|
|
53
|
+
watch: false
|
|
44
54
|
},
|
|
45
|
-
|
|
46
|
-
|
|
55
|
+
false
|
|
56
|
+
)
|
|
47
57
|
|
|
48
58
|
const tsOptions = await extract(configManager, app)
|
|
49
59
|
|
|
@@ -52,7 +62,7 @@ async function compile (argv, logger) {
|
|
|
52
62
|
...compileOptions,
|
|
53
63
|
...tsOptions,
|
|
54
64
|
cwd: service.path,
|
|
55
|
-
logger: childLogger
|
|
65
|
+
logger: childLogger
|
|
56
66
|
})
|
|
57
67
|
compiled ||= serviceWasCompiled
|
|
58
68
|
}
|
|
@@ -64,7 +74,7 @@ async function compile (argv, logger) {
|
|
|
64
74
|
...compileOptions,
|
|
65
75
|
...tsOptions,
|
|
66
76
|
cwd: dirname(configManager.fullPath),
|
|
67
|
-
logger
|
|
77
|
+
logger
|
|
68
78
|
})
|
|
69
79
|
}
|
|
70
80
|
}
|
|
@@ -81,9 +91,9 @@ async function extract (configManager, app) {
|
|
|
81
91
|
const _require = createRequire(join(configManager.dirname, 'package.json'))
|
|
82
92
|
const toLoad = _require.resolve('@platformatic/service')
|
|
83
93
|
try {
|
|
84
|
-
extractTypeScriptCompileOptionsFromConfig = (await import(pathToFileURL(toLoad)))
|
|
85
|
-
|
|
86
|
-
}
|
|
94
|
+
extractTypeScriptCompileOptionsFromConfig = (await import(pathToFileURL(toLoad)))
|
|
95
|
+
.extractTypeScriptCompileOptionsFromConfig
|
|
96
|
+
} catch {}
|
|
87
97
|
// If we can't load `@platformatic/service` we just return null
|
|
88
98
|
// and we won't be compiling typescript
|
|
89
99
|
}
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
const { BaseGenerator } = require('@platformatic/generators')
|
|
4
4
|
const { NoEntryPointError, NoServiceNamedError } = require('./errors')
|
|
5
|
-
const generateName = require('boring-name-generator')
|
|
6
5
|
const { join } = require('node:path')
|
|
7
6
|
const { envObjectToString } = require('@platformatic/generators/lib/utils')
|
|
8
7
|
const { readFile, readdir, stat } = require('node:fs/promises')
|
|
@@ -11,15 +10,14 @@ const { platformaticRuntime } = require('../config')
|
|
|
11
10
|
const { getServiceTemplateFromSchemaUrl } = require('@platformatic/generators/lib/utils')
|
|
12
11
|
const { DotEnvTool } = require('dotenv-tool')
|
|
13
12
|
const { getArrayDifference } = require('../utils')
|
|
14
|
-
const { createRequire } = require('node:module')
|
|
15
13
|
const { pathToFileURL } = require('node:url')
|
|
16
|
-
const { safeRemove } = require('@platformatic/utils')
|
|
14
|
+
const { createRequire, safeRemove, generateDashedName } = require('@platformatic/utils')
|
|
17
15
|
|
|
18
16
|
class RuntimeGenerator extends BaseGenerator {
|
|
19
17
|
constructor (opts) {
|
|
20
18
|
super({
|
|
21
19
|
...opts,
|
|
22
|
-
module: '@platformatic/runtime'
|
|
20
|
+
module: '@platformatic/runtime'
|
|
23
21
|
})
|
|
24
22
|
this.runtimeName = opts.name
|
|
25
23
|
this.services = []
|
|
@@ -29,18 +27,18 @@ class RuntimeGenerator extends BaseGenerator {
|
|
|
29
27
|
async addService (service, name) {
|
|
30
28
|
// ensure service config is correct
|
|
31
29
|
const originalConfig = service.config
|
|
32
|
-
const serviceName = name ||
|
|
30
|
+
const serviceName = name || generateDashedName()
|
|
33
31
|
const newConfig = {
|
|
34
32
|
...originalConfig,
|
|
35
33
|
isRuntimeContext: true,
|
|
36
|
-
serviceName
|
|
34
|
+
serviceName
|
|
37
35
|
}
|
|
38
36
|
// reset all files previously generated by the service
|
|
39
37
|
service.reset()
|
|
40
38
|
service.setConfig(newConfig)
|
|
41
39
|
this.services.push({
|
|
42
40
|
name: serviceName,
|
|
43
|
-
service
|
|
41
|
+
service
|
|
44
42
|
})
|
|
45
43
|
|
|
46
44
|
if (typeof service.setRuntime === 'function') {
|
|
@@ -61,20 +59,20 @@ class RuntimeGenerator extends BaseGenerator {
|
|
|
61
59
|
name: `${this.runtimeName}`,
|
|
62
60
|
workspaces: ['services/*'],
|
|
63
61
|
scripts: {
|
|
64
|
-
start: 'platformatic start'
|
|
62
|
+
start: 'platformatic start'
|
|
65
63
|
},
|
|
66
64
|
devDependencies: {
|
|
67
65
|
fastify: `^${this.fastifyVersion}`,
|
|
68
|
-
borp: `${this.pkgData.devDependencies.borp}
|
|
66
|
+
borp: `${this.pkgData.devDependencies.borp}`
|
|
69
67
|
},
|
|
70
68
|
dependencies: {
|
|
71
69
|
'@platformatic/runtime': `^${this.platformaticVersion}`,
|
|
72
70
|
platformatic: `^${this.platformaticVersion}`,
|
|
73
|
-
...this.config.dependencies
|
|
71
|
+
...this.config.dependencies
|
|
74
72
|
},
|
|
75
73
|
engines: {
|
|
76
|
-
node: '^18.8.0 || >=20.6.0'
|
|
77
|
-
}
|
|
74
|
+
node: '^18.8.0 || >=20.6.0'
|
|
75
|
+
}
|
|
78
76
|
}
|
|
79
77
|
if (this.config.typescript) {
|
|
80
78
|
const typescriptVersion = JSON.parse(await readFile(join(__dirname, '..', '..', 'package.json'), 'utf-8'))
|
|
@@ -96,7 +94,7 @@ class RuntimeGenerator extends BaseGenerator {
|
|
|
96
94
|
PLT_SERVER_HOSTNAME: '127.0.0.1',
|
|
97
95
|
PORT: this.config.port || 3042,
|
|
98
96
|
PLT_SERVER_LOGGER_LEVEL: this.config.logLevel || 'info',
|
|
99
|
-
PLT_MANAGEMENT_API: true
|
|
97
|
+
PLT_MANAGEMENT_API: true
|
|
100
98
|
},
|
|
101
99
|
{ overwrite: false, default: true }
|
|
102
100
|
)
|
|
@@ -121,7 +119,7 @@ class RuntimeGenerator extends BaseGenerator {
|
|
|
121
119
|
if (existingConfigFile) {
|
|
122
120
|
const configManager = new ConfigManager({
|
|
123
121
|
...platformaticRuntime.configManagerConfig,
|
|
124
|
-
source: join(this.targetDirectory, existingConfigFile)
|
|
122
|
+
source: join(this.targetDirectory, existingConfigFile)
|
|
125
123
|
})
|
|
126
124
|
await configManager.parse()
|
|
127
125
|
this.existingConfig = configManager.current
|
|
@@ -139,7 +137,7 @@ class RuntimeGenerator extends BaseGenerator {
|
|
|
139
137
|
await this._afterPrepare()
|
|
140
138
|
return {
|
|
141
139
|
env: this.config.env,
|
|
142
|
-
targetDirectory: this.targetDirectory
|
|
140
|
+
targetDirectory: this.targetDirectory
|
|
143
141
|
}
|
|
144
142
|
} else {
|
|
145
143
|
return await super.prepare()
|
|
@@ -163,16 +161,16 @@ class RuntimeGenerator extends BaseGenerator {
|
|
|
163
161
|
watch: true,
|
|
164
162
|
autoload: {
|
|
165
163
|
path: this.config.autoload || 'services',
|
|
166
|
-
exclude: ['docs']
|
|
164
|
+
exclude: ['docs']
|
|
167
165
|
},
|
|
168
166
|
logger: {
|
|
169
|
-
level: '{PLT_SERVER_LOGGER_LEVEL}'
|
|
167
|
+
level: '{PLT_SERVER_LOGGER_LEVEL}'
|
|
170
168
|
},
|
|
171
169
|
server: {
|
|
172
170
|
hostname: '{PLT_SERVER_HOSTNAME}',
|
|
173
171
|
port: '{PORT}'
|
|
174
172
|
},
|
|
175
|
-
managementApi: '{PLT_MANAGEMENT_API}'
|
|
173
|
+
managementApi: '{PLT_MANAGEMENT_API}'
|
|
176
174
|
}
|
|
177
175
|
|
|
178
176
|
return config
|
|
@@ -186,19 +184,19 @@ class RuntimeGenerator extends BaseGenerator {
|
|
|
186
184
|
this.addEnvVars({
|
|
187
185
|
...this.config.env,
|
|
188
186
|
...this.getRuntimeEnv(),
|
|
189
|
-
...servicesEnv
|
|
187
|
+
...servicesEnv
|
|
190
188
|
})
|
|
191
189
|
|
|
192
190
|
this.addFile({
|
|
193
191
|
path: '',
|
|
194
192
|
file: '.env',
|
|
195
|
-
contents: envObjectToString(this.config.env)
|
|
193
|
+
contents: envObjectToString(this.config.env)
|
|
196
194
|
})
|
|
197
195
|
|
|
198
196
|
this.addFile({
|
|
199
197
|
path: '',
|
|
200
198
|
file: '.env.sample',
|
|
201
|
-
contents: envObjectToString(this.config.env)
|
|
199
|
+
contents: envObjectToString(this.config.env)
|
|
202
200
|
})
|
|
203
201
|
|
|
204
202
|
if (!this.existingConfig) {
|
|
@@ -207,7 +205,7 @@ class RuntimeGenerator extends BaseGenerator {
|
|
|
207
205
|
|
|
208
206
|
return {
|
|
209
207
|
targetDirectory: this.targetDirectory,
|
|
210
|
-
env: servicesEnv
|
|
208
|
+
env: servicesEnv
|
|
211
209
|
}
|
|
212
210
|
}
|
|
213
211
|
|
|
@@ -231,8 +229,8 @@ class RuntimeGenerator extends BaseGenerator {
|
|
|
231
229
|
default: false,
|
|
232
230
|
choices: [
|
|
233
231
|
{ name: 'yes', value: true },
|
|
234
|
-
{ name: 'no', value: false }
|
|
235
|
-
]
|
|
232
|
+
{ name: 'no', value: false }
|
|
233
|
+
]
|
|
236
234
|
})
|
|
237
235
|
|
|
238
236
|
if (this.existingConfig) {
|
|
@@ -244,7 +242,7 @@ class RuntimeGenerator extends BaseGenerator {
|
|
|
244
242
|
type: 'input',
|
|
245
243
|
name: 'port',
|
|
246
244
|
default: 3042,
|
|
247
|
-
message: 'What port do you want to use?'
|
|
245
|
+
message: 'What port do you want to use?'
|
|
248
246
|
})
|
|
249
247
|
}
|
|
250
248
|
|
|
@@ -269,7 +267,7 @@ class RuntimeGenerator extends BaseGenerator {
|
|
|
269
267
|
const originalConfig = service.config
|
|
270
268
|
service.setConfig({
|
|
271
269
|
...originalConfig,
|
|
272
|
-
...configToOverride
|
|
270
|
+
...configToOverride
|
|
273
271
|
})
|
|
274
272
|
})
|
|
275
273
|
}
|
|
@@ -280,12 +278,12 @@ class RuntimeGenerator extends BaseGenerator {
|
|
|
280
278
|
// Propagate TypeScript
|
|
281
279
|
svc.service.setConfig({
|
|
282
280
|
...svc.service.config,
|
|
283
|
-
typescript: this.config.typescript
|
|
281
|
+
typescript: this.config.typescript
|
|
284
282
|
})
|
|
285
283
|
const svcEnv = await svc.service.prepare()
|
|
286
284
|
servicesEnv = {
|
|
287
285
|
...servicesEnv,
|
|
288
|
-
...svcEnv.env
|
|
286
|
+
...svcEnv.env
|
|
289
287
|
}
|
|
290
288
|
}
|
|
291
289
|
return servicesEnv
|
|
@@ -301,7 +299,7 @@ class RuntimeGenerator extends BaseGenerator {
|
|
|
301
299
|
|
|
302
300
|
getRuntimeEnv () {
|
|
303
301
|
return {
|
|
304
|
-
PORT: this.config.port
|
|
302
|
+
PORT: this.config.port
|
|
305
303
|
}
|
|
306
304
|
}
|
|
307
305
|
|
|
@@ -319,7 +317,7 @@ class RuntimeGenerator extends BaseGenerator {
|
|
|
319
317
|
|
|
320
318
|
async loadFromDir () {
|
|
321
319
|
const output = {
|
|
322
|
-
services: []
|
|
320
|
+
services: []
|
|
323
321
|
}
|
|
324
322
|
const runtimePkgConfigFileData = JSON.parse(
|
|
325
323
|
await readFile(join(this.targetDirectory, 'platformatic.json'), 'utf-8')
|
|
@@ -339,7 +337,7 @@ class RuntimeGenerator extends BaseGenerator {
|
|
|
339
337
|
const template = servicePltJson.module || getServiceTemplateFromSchemaUrl(servicePltJson.$schema)
|
|
340
338
|
const Generator = await this._getGeneratorForTemplate(currentServicePath, template)
|
|
341
339
|
const instance = new Generator({
|
|
342
|
-
logger: this.logger
|
|
340
|
+
logger: this.logger
|
|
343
341
|
})
|
|
344
342
|
this.addService(instance, s)
|
|
345
343
|
output.services.push(await instance.loadFromDir(s, this.targetDirectory))
|
|
@@ -360,7 +358,7 @@ class RuntimeGenerator extends BaseGenerator {
|
|
|
360
358
|
const allNewServicesNames = newConfig.services.map(s => s.name)
|
|
361
359
|
// load dotenv tool
|
|
362
360
|
const envTool = new DotEnvTool({
|
|
363
|
-
path: join(this.targetDirectory, '.env')
|
|
361
|
+
path: join(this.targetDirectory, '.env')
|
|
364
362
|
})
|
|
365
363
|
|
|
366
364
|
await envTool.load()
|
|
@@ -402,13 +400,13 @@ class RuntimeGenerator extends BaseGenerator {
|
|
|
402
400
|
newService.template
|
|
403
401
|
)
|
|
404
402
|
const serviceInstance = new ServiceGenerator({
|
|
405
|
-
logger: this.logger
|
|
403
|
+
logger: this.logger
|
|
406
404
|
})
|
|
407
405
|
const baseConfig = {
|
|
408
406
|
isRuntimeContext: true,
|
|
409
407
|
targetDirectory: join(this.targetDirectory, 'services', newService.name),
|
|
410
408
|
serviceName: newService.name,
|
|
411
|
-
plugin: true
|
|
409
|
+
plugin: true
|
|
412
410
|
}
|
|
413
411
|
if (allCurrentServicesNames.includes(newService.name)) {
|
|
414
412
|
// update existing services env values
|
|
@@ -425,7 +423,7 @@ class RuntimeGenerator extends BaseGenerator {
|
|
|
425
423
|
// add service to the generator
|
|
426
424
|
this.services.push({
|
|
427
425
|
name: newService.name,
|
|
428
|
-
service: serviceInstance
|
|
426
|
+
service: serviceInstance
|
|
429
427
|
})
|
|
430
428
|
}
|
|
431
429
|
serviceInstance.setConfig(baseConfig)
|
|
@@ -464,12 +462,12 @@ class RuntimeGenerator extends BaseGenerator {
|
|
|
464
462
|
// update runtime package.json dependencies
|
|
465
463
|
currrentPackageJson.dependencies = {
|
|
466
464
|
...currrentPackageJson.dependencies,
|
|
467
|
-
...allServicesDependencies
|
|
465
|
+
...allServicesDependencies
|
|
468
466
|
}
|
|
469
467
|
this.addFile({
|
|
470
468
|
path: '',
|
|
471
469
|
file: 'package.json',
|
|
472
|
-
contents: JSON.stringify(currrentPackageJson, null, 2)
|
|
470
|
+
contents: JSON.stringify(currrentPackageJson, null, 2)
|
|
473
471
|
})
|
|
474
472
|
|
|
475
473
|
// set new entrypoint if specified
|
|
@@ -485,7 +483,7 @@ class RuntimeGenerator extends BaseGenerator {
|
|
|
485
483
|
this.addFile({
|
|
486
484
|
path: '',
|
|
487
485
|
file: 'platformatic.json',
|
|
488
|
-
contents: JSON.stringify(runtimePkgConfigFileData, null, 2)
|
|
486
|
+
contents: JSON.stringify(runtimePkgConfigFileData, null, 2)
|
|
489
487
|
})
|
|
490
488
|
}
|
|
491
489
|
await this.writeFiles()
|
package/lib/runtime.js
CHANGED
|
@@ -3,10 +3,12 @@
|
|
|
3
3
|
const { once, EventEmitter } = require('node:events')
|
|
4
4
|
const { createReadStream, watch, existsSync } = require('node:fs')
|
|
5
5
|
const { readdir, readFile, stat, access } = require('node:fs/promises')
|
|
6
|
+
const { STATUS_CODES } = require('node:http')
|
|
6
7
|
const { join } = require('node:path')
|
|
7
8
|
const { setTimeout: sleep } = require('node:timers/promises')
|
|
8
9
|
const { Worker } = require('node:worker_threads')
|
|
9
10
|
const { ITC } = require('@platformatic/itc')
|
|
11
|
+
const { Agent, interceptors: undiciInterceptors, request } = require('undici')
|
|
10
12
|
const { ensureLoggableError, executeWithTimeout, deepmerge } = require('@platformatic/utils')
|
|
11
13
|
const ts = require('tail-file-stream')
|
|
12
14
|
const { createThreadInterceptor } = require('undici-thread-interceptor')
|
|
@@ -61,7 +63,8 @@ class Runtime extends EventEmitter {
|
|
|
61
63
|
#metrics
|
|
62
64
|
#metricsTimeout
|
|
63
65
|
#status
|
|
64
|
-
#
|
|
66
|
+
#meshInterceptor
|
|
67
|
+
#dispatcher
|
|
65
68
|
#managementApi
|
|
66
69
|
#prometheusServer
|
|
67
70
|
#inspectorServer
|
|
@@ -80,8 +83,7 @@ class Runtime extends EventEmitter {
|
|
|
80
83
|
this.#workers = new RoundRobinMap()
|
|
81
84
|
this.#servicesIds = []
|
|
82
85
|
this.#url = undefined
|
|
83
|
-
|
|
84
|
-
this.#interceptor = createThreadInterceptor({
|
|
86
|
+
this.#meshInterceptor = createThreadInterceptor({
|
|
85
87
|
domain: '.plt.local',
|
|
86
88
|
timeout: this.#configManager.current.serviceTimeout
|
|
87
89
|
})
|
|
@@ -182,10 +184,17 @@ class Runtime extends EventEmitter {
|
|
|
182
184
|
throw e
|
|
183
185
|
}
|
|
184
186
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
)
|
|
187
|
+
const dispatcherOpts = { ...config.undici }
|
|
188
|
+
const interceptors = [this.#meshInterceptor]
|
|
189
|
+
|
|
190
|
+
if (config.httpCache) {
|
|
191
|
+
this.#sharedHttpCache = await createSharedStore(this.#configManager.dirname, config.httpCache)
|
|
192
|
+
interceptors.push(
|
|
193
|
+
undiciInterceptors.cache({ store: this.#sharedHttpCache, methods: config.httpCache.methods ?? ['GET', 'HEAD'] })
|
|
194
|
+
)
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
this.#dispatcher = new Agent(dispatcherOpts).compose(interceptors)
|
|
189
198
|
|
|
190
199
|
this.#updateStatus('init')
|
|
191
200
|
}
|
|
@@ -375,8 +384,48 @@ class Runtime extends EventEmitter {
|
|
|
375
384
|
}
|
|
376
385
|
|
|
377
386
|
async inject (id, injectParams) {
|
|
378
|
-
|
|
379
|
-
|
|
387
|
+
// Make sure the service exists
|
|
388
|
+
await this.#getServiceById(id, true)
|
|
389
|
+
|
|
390
|
+
if (typeof injectParams === 'string') {
|
|
391
|
+
injectParams = { url: injectParams }
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
let { method, headers, body } = injectParams
|
|
395
|
+
const url = new URL(injectParams.url, `http://${id}.plt.local`)
|
|
396
|
+
|
|
397
|
+
if (injectParams.query) {
|
|
398
|
+
for (const [k, v] of Object.entries(injectParams.query)) {
|
|
399
|
+
url.searchParams.append(k, v)
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
// Stringify the body as JSON if needed
|
|
404
|
+
if (
|
|
405
|
+
body &&
|
|
406
|
+
typeof body === 'object' &&
|
|
407
|
+
headers &&
|
|
408
|
+
Object.entries(headers).some(([k, v]) => k.toLowerCase() === 'content-type' && v.includes('application/json'))
|
|
409
|
+
) {
|
|
410
|
+
body = JSON.stringify(body)
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
const {
|
|
414
|
+
statusCode: responseStatus,
|
|
415
|
+
headers: responseHeaders,
|
|
416
|
+
body: responseRawBody
|
|
417
|
+
} = await request(url.toString(), { method, headers, body, dispatcher: this.#dispatcher })
|
|
418
|
+
const responsePayload = await responseRawBody.arrayBuffer()
|
|
419
|
+
const responseBody = Buffer.from(responsePayload).toString('utf-8')
|
|
420
|
+
|
|
421
|
+
return {
|
|
422
|
+
statusCode: responseStatus,
|
|
423
|
+
statusMessage: STATUS_CODES[responseStatus] || 'unknown',
|
|
424
|
+
headers: responseHeaders,
|
|
425
|
+
body: responseBody,
|
|
426
|
+
payload: responseBody,
|
|
427
|
+
rawPayload: responsePayload
|
|
428
|
+
}
|
|
380
429
|
}
|
|
381
430
|
|
|
382
431
|
startCollectingMetrics () {
|
|
@@ -520,7 +569,11 @@ class Runtime extends EventEmitter {
|
|
|
520
569
|
}
|
|
521
570
|
|
|
522
571
|
getInterceptor () {
|
|
523
|
-
return this.#
|
|
572
|
+
return this.#meshInterceptor
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
getDispatcher () {
|
|
576
|
+
return this.#dispatcher
|
|
524
577
|
}
|
|
525
578
|
|
|
526
579
|
getManagementApi () {
|
|
@@ -781,10 +834,36 @@ class Runtime extends EventEmitter {
|
|
|
781
834
|
return createReadStream(filePath)
|
|
782
835
|
}
|
|
783
836
|
|
|
784
|
-
|
|
837
|
+
#getHttpCacheValue ({ request }) {
|
|
838
|
+
if (!this.#sharedHttpCache) {
|
|
839
|
+
return
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
return this.#sharedHttpCache.getValue(request)
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
#setHttpCacheValue ({ request, response, payload }) {
|
|
846
|
+
if (!this.#sharedHttpCache) {
|
|
847
|
+
return
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
return this.#sharedHttpCache.setValue(request, response, payload)
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
#deleteHttpCacheValue ({ request }) {
|
|
854
|
+
if (!this.#sharedHttpCache) {
|
|
855
|
+
return
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
return this.#sharedHttpCache.delete(request)
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
invalidateHttpCache (options = {}) {
|
|
785
862
|
const { keys, tags } = options
|
|
786
863
|
|
|
787
|
-
if (!this.#sharedHttpCache)
|
|
864
|
+
if (!this.#sharedHttpCache) {
|
|
865
|
+
return
|
|
866
|
+
}
|
|
788
867
|
|
|
789
868
|
const promises = []
|
|
790
869
|
if (keys && keys.length > 0) {
|
|
@@ -795,7 +874,7 @@ class Runtime extends EventEmitter {
|
|
|
795
874
|
promises.push(this.#sharedHttpCache.deleteTags(tags))
|
|
796
875
|
}
|
|
797
876
|
|
|
798
|
-
|
|
877
|
+
return Promise.all(promises)
|
|
799
878
|
}
|
|
800
879
|
|
|
801
880
|
async sendCommandToService (id, name, message) {
|
|
@@ -862,6 +941,16 @@ class Runtime extends EventEmitter {
|
|
|
862
941
|
const errorLabel = this.#workerExtendedLabel(serviceId, index, workersCount)
|
|
863
942
|
const health = deepmerge(config.health ?? {}, serviceConfig.health ?? {})
|
|
864
943
|
|
|
944
|
+
const execArgv = []
|
|
945
|
+
|
|
946
|
+
if (!serviceConfig.isPLTService) {
|
|
947
|
+
execArgv.push('--require', openTelemetrySetupPath)
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
if ((serviceConfig.sourceMaps ?? config.sourceMaps) === true) {
|
|
951
|
+
execArgv.push('--enable-source-maps')
|
|
952
|
+
}
|
|
953
|
+
|
|
865
954
|
const worker = new Worker(kWorkerFile, {
|
|
866
955
|
workerData: {
|
|
867
956
|
config,
|
|
@@ -879,7 +968,7 @@ class Runtime extends EventEmitter {
|
|
|
879
968
|
runtimeLogsDir: this.#runtimeLogsDir,
|
|
880
969
|
loggingPort
|
|
881
970
|
},
|
|
882
|
-
execArgv
|
|
971
|
+
execArgv,
|
|
883
972
|
env: this.#env,
|
|
884
973
|
transferList: [loggingPort],
|
|
885
974
|
resourceLimits: {
|
|
@@ -956,16 +1045,10 @@ class Runtime extends EventEmitter {
|
|
|
956
1045
|
getServiceMeta: this.getServiceMeta.bind(this),
|
|
957
1046
|
listServices: () => this.#servicesIds,
|
|
958
1047
|
getServices: this.getServices.bind(this),
|
|
959
|
-
getHttpCacheValue:
|
|
960
|
-
setHttpCacheValue:
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
opts.payload
|
|
964
|
-
),
|
|
965
|
-
deleteHttpCacheValue: opts => this.#sharedHttpCache.delete(
|
|
966
|
-
opts.request
|
|
967
|
-
),
|
|
968
|
-
invalidateHttpCache: opts => this.invalidateHttpCache(opts),
|
|
1048
|
+
getHttpCacheValue: this.#getHttpCacheValue.bind(this),
|
|
1049
|
+
setHttpCacheValue: this.#setHttpCacheValue.bind(this),
|
|
1050
|
+
deleteHttpCacheValue: this.#deleteHttpCacheValue.bind(this),
|
|
1051
|
+
invalidateHttpCache: this.invalidateHttpCache.bind(this)
|
|
969
1052
|
}
|
|
970
1053
|
})
|
|
971
1054
|
worker[kITC].listen()
|
|
@@ -1004,7 +1087,7 @@ class Runtime extends EventEmitter {
|
|
|
1004
1087
|
}
|
|
1005
1088
|
|
|
1006
1089
|
// Setup the interceptor
|
|
1007
|
-
this.#
|
|
1090
|
+
this.#meshInterceptor.route(serviceId, worker)
|
|
1008
1091
|
|
|
1009
1092
|
// Store dependencies
|
|
1010
1093
|
const [{ dependencies }] = await waitEventFromITC(worker, 'init')
|
package/lib/schema.js
CHANGED
|
@@ -44,6 +44,10 @@ const services = {
|
|
|
44
44
|
url: {
|
|
45
45
|
type: 'string'
|
|
46
46
|
},
|
|
47
|
+
gitBranch: {
|
|
48
|
+
type: 'string',
|
|
49
|
+
default: 'main'
|
|
50
|
+
},
|
|
47
51
|
useHttp: {
|
|
48
52
|
type: 'boolean'
|
|
49
53
|
},
|
|
@@ -52,6 +56,14 @@ const services = {
|
|
|
52
56
|
env,
|
|
53
57
|
envfile: {
|
|
54
58
|
type: 'string'
|
|
59
|
+
},
|
|
60
|
+
sourceMaps: {
|
|
61
|
+
type: 'boolean',
|
|
62
|
+
default: false
|
|
63
|
+
},
|
|
64
|
+
packageManager: {
|
|
65
|
+
type: 'string',
|
|
66
|
+
enum: ['npm', 'pnpm', 'yarn']
|
|
55
67
|
}
|
|
56
68
|
}
|
|
57
69
|
}
|
|
@@ -328,7 +340,11 @@ const platformaticRuntimeSchema = {
|
|
|
328
340
|
type: 'string',
|
|
329
341
|
default: 'external'
|
|
330
342
|
},
|
|
331
|
-
env
|
|
343
|
+
env,
|
|
344
|
+
sourceMaps: {
|
|
345
|
+
type: 'boolean',
|
|
346
|
+
default: false
|
|
347
|
+
}
|
|
332
348
|
},
|
|
333
349
|
anyOf: [{ required: ['autoload'] }, { required: ['services'] }, { required: ['web'] }],
|
|
334
350
|
additionalProperties: false,
|
package/lib/shared-http-cache.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const { join } = require('node:path')
|
|
4
|
-
const { createRequire } = require('
|
|
4
|
+
const { createRequire, loadModule } = require('@platformatic/utils')
|
|
5
5
|
const MemoryCacheStore = require('@platformatic/undici-cache-memory')
|
|
6
6
|
|
|
7
|
-
function createSharedStore (projectDir, httpCacheConfig = {}) {
|
|
7
|
+
async function createSharedStore (projectDir, httpCacheConfig = {}) {
|
|
8
8
|
const runtimeRequire = createRequire(join(projectDir, 'file'))
|
|
9
9
|
|
|
10
10
|
const { store, ...storeConfig } = httpCacheConfig
|
|
11
|
-
const CacheStore = store ? runtimeRequire
|
|
11
|
+
const CacheStore = store ? await loadModule(runtimeRequire, store) : MemoryCacheStore
|
|
12
12
|
|
|
13
13
|
class SharedCacheStore extends CacheStore {
|
|
14
14
|
async getValue (req) {
|
package/lib/worker/app.js
CHANGED
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
const { existsSync } = require('node:fs')
|
|
4
4
|
const { EventEmitter } = require('node:events')
|
|
5
5
|
const { resolve } = require('node:path')
|
|
6
|
-
const {
|
|
6
|
+
const {
|
|
7
|
+
performance: { eventLoopUtilization }
|
|
8
|
+
} = require('node:perf_hooks')
|
|
7
9
|
const { workerData } = require('node:worker_threads')
|
|
8
10
|
const { ConfigManager } = require('@platformatic/config')
|
|
9
11
|
const { FileWatcher } = require('@platformatic/utils')
|
|
@@ -128,10 +130,6 @@ class PlatformaticApp extends EventEmitter {
|
|
|
128
130
|
})
|
|
129
131
|
this.stackable = this.#wrapStackable(stackable)
|
|
130
132
|
|
|
131
|
-
this.once('start', () => {
|
|
132
|
-
this.stackable.collectMetrics()
|
|
133
|
-
})
|
|
134
|
-
|
|
135
133
|
this.#updateDispatcher()
|
|
136
134
|
} catch (err) {
|
|
137
135
|
if (err.validationErrors) {
|
|
@@ -9,9 +9,11 @@ async function loadInterceptor (_require, module, options) {
|
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
function loadInterceptors (_require, interceptors) {
|
|
12
|
-
return Promise.all(
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
return Promise.all(
|
|
13
|
+
interceptors.map(async ({ module, options }) => {
|
|
14
|
+
return loadInterceptor(_require, module, options)
|
|
15
|
+
})
|
|
16
|
+
)
|
|
15
17
|
}
|
|
16
18
|
|
|
17
|
-
module.exports = loadInterceptors
|
|
19
|
+
module.exports = { loadInterceptors }
|
package/lib/worker/main.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const { EventEmitter } = require('node:events')
|
|
4
|
-
const { createRequire } = require('
|
|
4
|
+
const { createRequire } = require('@platformatic/utils')
|
|
5
5
|
const { hostname } = require('node:os')
|
|
6
6
|
const { join, resolve } = require('node:path')
|
|
7
7
|
const { parentPort, workerData, threadId } = require('node:worker_threads')
|
|
@@ -19,7 +19,7 @@ const undici = require('undici')
|
|
|
19
19
|
const RemoteCacheStore = require('./http-cache')
|
|
20
20
|
const { PlatformaticApp } = require('./app')
|
|
21
21
|
const { setupITC } = require('./itc')
|
|
22
|
-
const loadInterceptors = require('./interceptors')
|
|
22
|
+
const { loadInterceptors } = require('./interceptors')
|
|
23
23
|
const { createTelemetryThreadInterceptorHooks } = require('@platformatic/telemetry')
|
|
24
24
|
|
|
25
25
|
const {
|
|
@@ -141,8 +141,7 @@ async function main () {
|
|
|
141
141
|
}
|
|
142
142
|
}
|
|
143
143
|
|
|
144
|
-
const globalDispatcher = new Agent(dispatcherOpts)
|
|
145
|
-
.compose(composedInterceptors)
|
|
144
|
+
const globalDispatcher = new Agent(dispatcherOpts).compose(composedInterceptors)
|
|
146
145
|
|
|
147
146
|
setGlobalDispatcher(globalDispatcher)
|
|
148
147
|
|
|
@@ -158,10 +157,12 @@ async function main () {
|
|
|
158
157
|
|
|
159
158
|
if (config.httpCache) {
|
|
160
159
|
setGlobalDispatcher(
|
|
161
|
-
getGlobalDispatcher().compose(
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
160
|
+
getGlobalDispatcher().compose(
|
|
161
|
+
undici.interceptors.cache({
|
|
162
|
+
store: new RemoteCacheStore(),
|
|
163
|
+
methods: config.httpCache.methods ?? ['GET', 'HEAD']
|
|
164
|
+
})
|
|
165
|
+
)
|
|
165
166
|
)
|
|
166
167
|
}
|
|
167
168
|
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
const { features } = require('@platformatic/utils')
|
|
4
|
+
|
|
3
5
|
class RoundRobinMap extends Map {
|
|
4
6
|
#instances
|
|
5
7
|
|
|
@@ -19,7 +21,7 @@ class RoundRobinMap extends Map {
|
|
|
19
21
|
for (const service of services) {
|
|
20
22
|
let count = service.workers ?? defaultInstances
|
|
21
23
|
|
|
22
|
-
if (service.entrypoint
|
|
24
|
+
if (!production || (service.entrypoint && !features.node.reusePort)) {
|
|
23
25
|
count = 1
|
|
24
26
|
}
|
|
25
27
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@platformatic/runtime",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.24.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -26,21 +26,21 @@
|
|
|
26
26
|
"express": "^4.18.3",
|
|
27
27
|
"fast-jwt": "^5.0.0",
|
|
28
28
|
"get-port": "^7.1.0",
|
|
29
|
-
"inspector-client": "^0.
|
|
29
|
+
"inspector-client": "^0.2.0",
|
|
30
30
|
"json-schema-to-typescript": "^15.0.0",
|
|
31
|
-
"neostandard": "^0.
|
|
31
|
+
"neostandard": "^0.12.0",
|
|
32
32
|
"pino-abstract-transport": "^2.0.0",
|
|
33
33
|
"split2": "^4.2.0",
|
|
34
34
|
"tsd": "^0.31.0",
|
|
35
35
|
"typescript": "^5.5.4",
|
|
36
36
|
"undici-oidc-interceptor": "^0.5.0",
|
|
37
37
|
"why-is-node-running": "^2.2.2",
|
|
38
|
-
"@platformatic/composer": "2.
|
|
39
|
-
"@platformatic/db": "2.
|
|
40
|
-
"@platformatic/node": "2.
|
|
41
|
-
"@platformatic/service": "2.
|
|
42
|
-
"@platformatic/sql-
|
|
43
|
-
"@platformatic/sql-
|
|
38
|
+
"@platformatic/composer": "2.24.0",
|
|
39
|
+
"@platformatic/db": "2.24.0",
|
|
40
|
+
"@platformatic/node": "2.24.0",
|
|
41
|
+
"@platformatic/service": "2.24.0",
|
|
42
|
+
"@platformatic/sql-graphql": "2.24.0",
|
|
43
|
+
"@platformatic/sql-mapper": "2.24.0"
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
46
|
"@fastify/error": "^4.0.0",
|
|
@@ -49,7 +49,6 @@
|
|
|
49
49
|
"@platformatic/http-metrics": "^0.2.1",
|
|
50
50
|
"@platformatic/undici-cache-memory": "^0.8.1",
|
|
51
51
|
"@watchable/unpromise": "^1.0.2",
|
|
52
|
-
"boring-name-generator": "^1.0.3",
|
|
53
52
|
"change-case-all": "^2.1.0",
|
|
54
53
|
"close-with-grace": "^2.0.0",
|
|
55
54
|
"commist": "^3.2.0",
|
|
@@ -73,13 +72,13 @@
|
|
|
73
72
|
"undici": "^7.0.0",
|
|
74
73
|
"undici-thread-interceptor": "^0.10.0",
|
|
75
74
|
"ws": "^8.16.0",
|
|
76
|
-
"@platformatic/basic": "2.
|
|
77
|
-
"@platformatic/
|
|
78
|
-
"@platformatic/
|
|
79
|
-
"@platformatic/
|
|
80
|
-
"@platformatic/
|
|
81
|
-
"@platformatic/
|
|
82
|
-
"@platformatic/utils": "2.
|
|
75
|
+
"@platformatic/basic": "2.24.0",
|
|
76
|
+
"@platformatic/generators": "2.24.0",
|
|
77
|
+
"@platformatic/telemetry": "2.24.0",
|
|
78
|
+
"@platformatic/config": "2.24.0",
|
|
79
|
+
"@platformatic/itc": "2.24.0",
|
|
80
|
+
"@platformatic/ts-compiler": "2.24.0",
|
|
81
|
+
"@platformatic/utils": "2.24.0"
|
|
83
82
|
},
|
|
84
83
|
"scripts": {
|
|
85
84
|
"test": "npm run lint && borp --concurrency=1 --timeout=300000 && tsd",
|
package/schema.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"$id": "https://schemas.platformatic.dev/@platformatic/runtime/2.
|
|
2
|
+
"$id": "https://schemas.platformatic.dev/@platformatic/runtime/2.24.0.json",
|
|
3
3
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
4
4
|
"type": "object",
|
|
5
5
|
"properties": {
|
|
@@ -192,6 +192,10 @@
|
|
|
192
192
|
"url": {
|
|
193
193
|
"type": "string"
|
|
194
194
|
},
|
|
195
|
+
"gitBranch": {
|
|
196
|
+
"type": "string",
|
|
197
|
+
"default": "main"
|
|
198
|
+
},
|
|
195
199
|
"useHttp": {
|
|
196
200
|
"type": "boolean"
|
|
197
201
|
},
|
|
@@ -305,6 +309,18 @@
|
|
|
305
309
|
},
|
|
306
310
|
"envfile": {
|
|
307
311
|
"type": "string"
|
|
312
|
+
},
|
|
313
|
+
"sourceMaps": {
|
|
314
|
+
"type": "boolean",
|
|
315
|
+
"default": false
|
|
316
|
+
},
|
|
317
|
+
"packageManager": {
|
|
318
|
+
"type": "string",
|
|
319
|
+
"enum": [
|
|
320
|
+
"npm",
|
|
321
|
+
"pnpm",
|
|
322
|
+
"yarn"
|
|
323
|
+
]
|
|
308
324
|
}
|
|
309
325
|
}
|
|
310
326
|
}
|
|
@@ -354,6 +370,10 @@
|
|
|
354
370
|
"url": {
|
|
355
371
|
"type": "string"
|
|
356
372
|
},
|
|
373
|
+
"gitBranch": {
|
|
374
|
+
"type": "string",
|
|
375
|
+
"default": "main"
|
|
376
|
+
},
|
|
357
377
|
"useHttp": {
|
|
358
378
|
"type": "boolean"
|
|
359
379
|
},
|
|
@@ -467,6 +487,18 @@
|
|
|
467
487
|
},
|
|
468
488
|
"envfile": {
|
|
469
489
|
"type": "string"
|
|
490
|
+
},
|
|
491
|
+
"sourceMaps": {
|
|
492
|
+
"type": "boolean",
|
|
493
|
+
"default": false
|
|
494
|
+
},
|
|
495
|
+
"packageManager": {
|
|
496
|
+
"type": "string",
|
|
497
|
+
"enum": [
|
|
498
|
+
"npm",
|
|
499
|
+
"pnpm",
|
|
500
|
+
"yarn"
|
|
501
|
+
]
|
|
470
502
|
}
|
|
471
503
|
}
|
|
472
504
|
}
|
|
@@ -1137,6 +1169,10 @@
|
|
|
1137
1169
|
"additionalProperties": {
|
|
1138
1170
|
"type": "string"
|
|
1139
1171
|
}
|
|
1172
|
+
},
|
|
1173
|
+
"sourceMaps": {
|
|
1174
|
+
"type": "boolean",
|
|
1175
|
+
"default": false
|
|
1140
1176
|
}
|
|
1141
1177
|
},
|
|
1142
1178
|
"anyOf": [
|