@platformatic/runtime 2.7.1-alpha.2 → 2.8.0-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/config.d.ts +6 -12
- package/eslint.config.js +1 -1
- package/lib/config.js +1 -1
- package/lib/dependencies.js +15 -13
- package/lib/errors.js +3 -1
- package/lib/logger.js +22 -7
- package/lib/management-api.js +1 -10
- package/lib/runtime.js +318 -245
- package/lib/schema.js +41 -27
- package/lib/start.js +15 -9
- package/lib/worker/app.js +16 -2
- package/lib/worker/itc.js +7 -2
- package/lib/worker/main.js +22 -48
- package/lib/worker/round-robin-map.js +61 -0
- package/lib/worker/symbols.js +6 -1
- package/package.json +23 -18
- package/schema.json +70 -30
- package/lib/shared-http-cache.js +0 -45
- package/lib/worker/http-cache.js +0 -83
package/lib/schema.js
CHANGED
|
@@ -6,6 +6,16 @@ const {
|
|
|
6
6
|
schemaComponents: { server, logger }
|
|
7
7
|
} = require('@platformatic/utils')
|
|
8
8
|
|
|
9
|
+
const workers = {
|
|
10
|
+
anyOf: [
|
|
11
|
+
{
|
|
12
|
+
type: 'number',
|
|
13
|
+
minimum: 1
|
|
14
|
+
},
|
|
15
|
+
{ type: 'string' }
|
|
16
|
+
]
|
|
17
|
+
}
|
|
18
|
+
|
|
9
19
|
const services = {
|
|
10
20
|
type: 'array',
|
|
11
21
|
items: {
|
|
@@ -27,7 +37,8 @@ const services = {
|
|
|
27
37
|
},
|
|
28
38
|
useHttp: {
|
|
29
39
|
type: 'boolean'
|
|
30
|
-
}
|
|
40
|
+
},
|
|
41
|
+
workers
|
|
31
42
|
}
|
|
32
43
|
}
|
|
33
44
|
}
|
|
@@ -90,6 +101,7 @@ const platformaticRuntimeSchema = {
|
|
|
90
101
|
}
|
|
91
102
|
},
|
|
92
103
|
services,
|
|
104
|
+
workers: { ...workers, default: 1 },
|
|
93
105
|
web: services,
|
|
94
106
|
logger,
|
|
95
107
|
server,
|
|
@@ -103,6 +115,34 @@ const platformaticRuntimeSchema = {
|
|
|
103
115
|
}
|
|
104
116
|
]
|
|
105
117
|
},
|
|
118
|
+
gracefulShutdown: {
|
|
119
|
+
type: 'object',
|
|
120
|
+
properties: {
|
|
121
|
+
runtime: {
|
|
122
|
+
anyOf: [
|
|
123
|
+
{
|
|
124
|
+
type: 'number',
|
|
125
|
+
minimum: 1
|
|
126
|
+
},
|
|
127
|
+
{ type: 'string' }
|
|
128
|
+
],
|
|
129
|
+
default: 10000
|
|
130
|
+
},
|
|
131
|
+
service: {
|
|
132
|
+
anyOf: [
|
|
133
|
+
{
|
|
134
|
+
type: 'number',
|
|
135
|
+
minimum: 1
|
|
136
|
+
},
|
|
137
|
+
{ type: 'string' }
|
|
138
|
+
],
|
|
139
|
+
default: 10000
|
|
140
|
+
}
|
|
141
|
+
},
|
|
142
|
+
default: {},
|
|
143
|
+
required: ['runtime', 'service'],
|
|
144
|
+
additionalProperties: false
|
|
145
|
+
},
|
|
106
146
|
undici: {
|
|
107
147
|
type: 'object',
|
|
108
148
|
properties: {
|
|
@@ -145,32 +185,6 @@ const platformaticRuntimeSchema = {
|
|
|
145
185
|
}
|
|
146
186
|
}
|
|
147
187
|
},
|
|
148
|
-
httpCache: {
|
|
149
|
-
oneOf: [
|
|
150
|
-
{
|
|
151
|
-
type: 'boolean'
|
|
152
|
-
},
|
|
153
|
-
{
|
|
154
|
-
type: 'object',
|
|
155
|
-
properties: {
|
|
156
|
-
store: {
|
|
157
|
-
type: 'string'
|
|
158
|
-
},
|
|
159
|
-
methods: {
|
|
160
|
-
type: 'array',
|
|
161
|
-
items: {
|
|
162
|
-
type: 'string'
|
|
163
|
-
},
|
|
164
|
-
default: ['GET', 'HEAD'],
|
|
165
|
-
minItems: 1
|
|
166
|
-
},
|
|
167
|
-
cacheTagsHeader: {
|
|
168
|
-
type: 'string'
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
]
|
|
173
|
-
},
|
|
174
188
|
watch: {
|
|
175
189
|
anyOf: [
|
|
176
190
|
{
|
package/lib/start.js
CHANGED
|
@@ -18,6 +18,16 @@ const { Runtime } = require('./runtime')
|
|
|
18
18
|
const errors = require('./errors')
|
|
19
19
|
const { getRuntimeLogsDir, loadConfig } = require('./utils')
|
|
20
20
|
|
|
21
|
+
async function restartRuntime (runtime) {
|
|
22
|
+
runtime.logger.info('Received SIGUSR2, restarting all services ...')
|
|
23
|
+
|
|
24
|
+
try {
|
|
25
|
+
await runtime.restart()
|
|
26
|
+
} catch (err) {
|
|
27
|
+
runtime.logger.error({ err: ensureLoggableError(err) }, 'Failed to restart services.')
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
21
31
|
async function buildRuntime (configManager, env) {
|
|
22
32
|
env = env || process.env
|
|
23
33
|
|
|
@@ -35,14 +45,10 @@ async function buildRuntime (configManager, env) {
|
|
|
35
45
|
const runtime = new Runtime(configManager, runtimeLogsDir, env)
|
|
36
46
|
|
|
37
47
|
/* c8 ignore next 3 */
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
await runtime.restart()
|
|
43
|
-
} catch (err) {
|
|
44
|
-
runtime.logger.error({ err: ensureLoggableError(err) }, 'Failed to restart services.')
|
|
45
|
-
}
|
|
48
|
+
const restartListener = restartRuntime.bind(null, runtime)
|
|
49
|
+
process.on('SIGUSR2', restartListener)
|
|
50
|
+
runtime.on('closed', () => {
|
|
51
|
+
process.removeListener('SIGUSR2', restartListener)
|
|
46
52
|
})
|
|
47
53
|
|
|
48
54
|
try {
|
|
@@ -109,7 +115,7 @@ async function setupAndStartRuntime (config) {
|
|
|
109
115
|
})
|
|
110
116
|
)
|
|
111
117
|
logger.warn(`Port: ${originalPort} is already in use!`)
|
|
112
|
-
logger.warn(`
|
|
118
|
+
logger.warn(`Changing the port to ${runtimeConfig.current.server.port}`)
|
|
113
119
|
}
|
|
114
120
|
return { address, runtime }
|
|
115
121
|
}
|
package/lib/worker/app.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
const { existsSync } = require('node:fs')
|
|
4
4
|
const { EventEmitter } = require('node:events')
|
|
5
5
|
const { resolve } = require('node:path')
|
|
6
|
+
const { workerData } = require('node:worker_threads')
|
|
6
7
|
const { ConfigManager } = require('@platformatic/config')
|
|
7
8
|
const { FileWatcher } = require('@platformatic/utils')
|
|
8
9
|
const { getGlobalDispatcher, setGlobalDispatcher } = require('undici')
|
|
@@ -21,9 +22,20 @@ class PlatformaticApp extends EventEmitter {
|
|
|
21
22
|
#debouncedRestart
|
|
22
23
|
#context
|
|
23
24
|
|
|
24
|
-
constructor (
|
|
25
|
+
constructor (
|
|
26
|
+
appConfig,
|
|
27
|
+
workerId,
|
|
28
|
+
telemetryConfig,
|
|
29
|
+
loggerConfig,
|
|
30
|
+
serverConfig,
|
|
31
|
+
metricsConfig,
|
|
32
|
+
hasManagementApi,
|
|
33
|
+
watch
|
|
34
|
+
) {
|
|
25
35
|
super()
|
|
26
36
|
this.appConfig = appConfig
|
|
37
|
+
this.serviceId = this.appConfig.id
|
|
38
|
+
this.workerId = workerId
|
|
27
39
|
this.#watch = watch
|
|
28
40
|
this.#starting = false
|
|
29
41
|
this.#started = false
|
|
@@ -32,7 +44,8 @@ class PlatformaticApp extends EventEmitter {
|
|
|
32
44
|
this.#fileWatcher = null
|
|
33
45
|
|
|
34
46
|
this.#context = {
|
|
35
|
-
serviceId: this.
|
|
47
|
+
serviceId: this.serviceId,
|
|
48
|
+
workerId: this.workerId,
|
|
36
49
|
directory: this.appConfig.path,
|
|
37
50
|
isEntrypoint: this.appConfig.entrypoint,
|
|
38
51
|
isProduction: this.appConfig.isProduction,
|
|
@@ -40,6 +53,7 @@ class PlatformaticApp extends EventEmitter {
|
|
|
40
53
|
metricsConfig,
|
|
41
54
|
loggerConfig,
|
|
42
55
|
serverConfig,
|
|
56
|
+
worker: workerData?.worker,
|
|
43
57
|
hasManagementApi: !!hasManagementApi,
|
|
44
58
|
localServiceEnvVars: this.appConfig.localServiceEnvVars
|
|
45
59
|
}
|
package/lib/worker/itc.js
CHANGED
|
@@ -7,7 +7,7 @@ const { ITC } = require('@platformatic/itc')
|
|
|
7
7
|
const { Unpromise } = require('@watchable/unpromise')
|
|
8
8
|
|
|
9
9
|
const errors = require('../errors')
|
|
10
|
-
const { kITC, kId } = require('./symbols')
|
|
10
|
+
const { kITC, kId, kServiceId, kWorkerId } = require('./symbols')
|
|
11
11
|
|
|
12
12
|
async function safeHandleInITC (worker, fn) {
|
|
13
13
|
try {
|
|
@@ -23,7 +23,11 @@ async function safeHandleInITC (worker, fn) {
|
|
|
23
23
|
])
|
|
24
24
|
|
|
25
25
|
if (typeof exitCode === 'number') {
|
|
26
|
-
|
|
26
|
+
if (typeof worker[kWorkerId] !== 'undefined') {
|
|
27
|
+
throw new errors.WorkerExitedError(worker[kWorkerId], worker[kServiceId], exitCode)
|
|
28
|
+
} else {
|
|
29
|
+
throw new errors.ServiceExitedError(worker[kId], exitCode)
|
|
30
|
+
}
|
|
27
31
|
} else {
|
|
28
32
|
ac.abort()
|
|
29
33
|
}
|
|
@@ -156,6 +160,7 @@ function setupITC (app, service, dispatcher) {
|
|
|
156
160
|
itc.notify('changed')
|
|
157
161
|
})
|
|
158
162
|
|
|
163
|
+
itc.listen()
|
|
159
164
|
return itc
|
|
160
165
|
}
|
|
161
166
|
|
package/lib/worker/main.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const { createRequire } = require('node:module')
|
|
4
|
+
const { hostname } = require('node:os')
|
|
4
5
|
const { join } = require('node:path')
|
|
5
6
|
const { parentPort, workerData, threadId } = require('node:worker_threads')
|
|
6
7
|
const { pathToFileURL } = require('node:url')
|
|
@@ -9,11 +10,9 @@ const diagnosticChannel = require('node:diagnostics_channel')
|
|
|
9
10
|
const { ServerResponse } = require('node:http')
|
|
10
11
|
|
|
11
12
|
const pino = require('pino')
|
|
12
|
-
const { fetch, setGlobalDispatcher,
|
|
13
|
+
const { fetch, setGlobalDispatcher, Agent } = require('undici')
|
|
13
14
|
const { wire } = require('undici-thread-interceptor')
|
|
14
|
-
const undici = require('undici')
|
|
15
15
|
|
|
16
|
-
const RemoteCacheStore = require('./http-cache')
|
|
17
16
|
const { PlatformaticApp } = require('./app')
|
|
18
17
|
const { setupITC } = require('./itc')
|
|
19
18
|
const loadInterceptors = require('./interceptors')
|
|
@@ -32,14 +31,17 @@ globalThis.fetch = fetch
|
|
|
32
31
|
globalThis[kId] = threadId
|
|
33
32
|
|
|
34
33
|
let app
|
|
34
|
+
|
|
35
35
|
const config = workerData.config
|
|
36
36
|
globalThis.platformatic = Object.assign(globalThis.platformatic ?? {}, { logger: createLogger() })
|
|
37
37
|
|
|
38
38
|
function handleUnhandled (type, err) {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
39
|
+
const label =
|
|
40
|
+
workerData.worker.count > 1
|
|
41
|
+
? `worker ${workerData.worker.index} of the service "${workerData.serviceConfig.id}"`
|
|
42
|
+
: `service "${workerData.serviceConfig.id}"`
|
|
43
|
+
|
|
44
|
+
globalThis.platformatic.logger.error({ err: ensureLoggableError(err) }, `The ${label} threw an ${type}.`)
|
|
43
45
|
|
|
44
46
|
executeWithTimeout(app?.stop(), 1000)
|
|
45
47
|
.catch()
|
|
@@ -50,7 +52,13 @@ function handleUnhandled (type, err) {
|
|
|
50
52
|
|
|
51
53
|
function createLogger () {
|
|
52
54
|
const destination = new MessagePortWritable({ port: workerData.loggingPort })
|
|
53
|
-
const
|
|
55
|
+
const pinoOptions = { level: 'trace', name: workerData.serviceConfig.id }
|
|
56
|
+
|
|
57
|
+
if (typeof workerData.worker?.index !== 'undefined') {
|
|
58
|
+
pinoOptions.base = { pid: process.pid, hostname: hostname(), worker: workerData.worker.index }
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const loggerInstance = pino(pinoOptions, destination)
|
|
54
62
|
|
|
55
63
|
Reflect.defineProperty(process, 'stdout', { value: createPinoWritable(loggerInstance, 'info') })
|
|
56
64
|
Reflect.defineProperty(process, 'stderr', { value: createPinoWritable(loggerInstance, 'error') })
|
|
@@ -82,34 +90,10 @@ async function main () {
|
|
|
82
90
|
}
|
|
83
91
|
}
|
|
84
92
|
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
const poolInterceptors = []
|
|
90
|
-
|
|
91
|
-
if (interceptors.Agent) {
|
|
92
|
-
clientInterceptors.push(...interceptors.Agent)
|
|
93
|
-
poolInterceptors.push(...interceptors.Agent)
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
if (interceptors.Pool) {
|
|
97
|
-
poolInterceptors.push(...interceptors.Pool)
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
if (interceptors.Client) {
|
|
101
|
-
clientInterceptors.push(...interceptors.Client)
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
dispatcherOpts.factory = (origin, opts) => {
|
|
105
|
-
return opts && opts.connections === 1
|
|
106
|
-
? new undici.Client(origin, opts).compose(clientInterceptors)
|
|
107
|
-
: new undici.Pool(origin, opts).compose(poolInterceptors)
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
const globalDispatcher = new Agent(dispatcherOpts)
|
|
112
|
-
.compose(composedInterceptors)
|
|
93
|
+
const globalDispatcher = new Agent({
|
|
94
|
+
...config.undici,
|
|
95
|
+
interceptors
|
|
96
|
+
}).compose(composedInterceptors)
|
|
113
97
|
|
|
114
98
|
setGlobalDispatcher(globalDispatcher)
|
|
115
99
|
|
|
@@ -118,15 +102,6 @@ async function main () {
|
|
|
118
102
|
// TODO: make this configurable
|
|
119
103
|
const threadDispatcher = wire({ port: parentPort, useNetwork: service.useHttp, timeout: 5 * 60 * 1000 })
|
|
120
104
|
|
|
121
|
-
if (config.httpCache) {
|
|
122
|
-
setGlobalDispatcher(
|
|
123
|
-
getGlobalDispatcher().compose(undici.interceptors.cache({
|
|
124
|
-
store: new RemoteCacheStore(),
|
|
125
|
-
methods: config.httpCache.methods ?? ['GET', 'HEAD']
|
|
126
|
-
}))
|
|
127
|
-
)
|
|
128
|
-
}
|
|
129
|
-
|
|
130
105
|
// If the service is an entrypoint and runtime server config is defined, use it.
|
|
131
106
|
let serverConfig = null
|
|
132
107
|
if (config.server && service.entrypoint) {
|
|
@@ -168,6 +143,7 @@ async function main () {
|
|
|
168
143
|
// Create the application
|
|
169
144
|
app = new PlatformaticApp(
|
|
170
145
|
service,
|
|
146
|
+
workerData.worker.count > 1 ? workerData.worker.index : undefined,
|
|
171
147
|
telemetryConfig,
|
|
172
148
|
config.logger,
|
|
173
149
|
serverConfig,
|
|
@@ -187,13 +163,11 @@ async function main () {
|
|
|
187
163
|
|
|
188
164
|
// Setup interaction with parent port
|
|
189
165
|
const itc = setupITC(app, service, threadDispatcher)
|
|
166
|
+
globalThis[kITC] = itc
|
|
190
167
|
|
|
191
168
|
// Get the dependencies
|
|
192
169
|
const dependencies = config.autoload ? await app.getBootstrapDependencies() : []
|
|
193
170
|
itc.notify('init', { dependencies })
|
|
194
|
-
itc.listen()
|
|
195
|
-
|
|
196
|
-
globalThis[kITC] = itc
|
|
197
171
|
}
|
|
198
172
|
|
|
199
173
|
function stripBasePath (basePath) {
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
class RoundRobinMap extends Map {
|
|
4
|
+
#instances
|
|
5
|
+
|
|
6
|
+
constructor (iterable, instances) {
|
|
7
|
+
super(iterable)
|
|
8
|
+
this.#instances = instances
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
get configuration () {
|
|
12
|
+
return { ...this.#instances }
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// In development or for the entrypoint always use 1 worker
|
|
16
|
+
configure (services, defaultInstances, production) {
|
|
17
|
+
this.#instances = {}
|
|
18
|
+
|
|
19
|
+
for (const service of services) {
|
|
20
|
+
let count = service.workers ?? defaultInstances
|
|
21
|
+
|
|
22
|
+
if (service.entrypoint || !production) {
|
|
23
|
+
count = 1
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
this.#instances[service.id] = { next: 0, count }
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
getCount (service) {
|
|
31
|
+
return this.#instances[service].count
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
next (service) {
|
|
35
|
+
if (!this.#instances[service]) {
|
|
36
|
+
return undefined
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
let worker
|
|
40
|
+
let { next, count } = this.#instances[service]
|
|
41
|
+
|
|
42
|
+
// Try count times to get the next worker. This is to handle the case where a worker is being restarted.
|
|
43
|
+
for (let i = 0; i < count; i++) {
|
|
44
|
+
const current = next++
|
|
45
|
+
if (next >= count) {
|
|
46
|
+
next = 0
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
worker = this.get(`${service}:${current}`)
|
|
50
|
+
|
|
51
|
+
if (worker) {
|
|
52
|
+
break
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
this.#instances[service].next = next
|
|
57
|
+
return worker
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
module.exports = { RoundRobinMap }
|
package/lib/worker/symbols.js
CHANGED
|
@@ -2,6 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
const kConfig = Symbol.for('plt.runtime.config')
|
|
4
4
|
const kId = Symbol.for('plt.runtime.id') // This is also used to detect if we are running in a Platformatic runtime thread
|
|
5
|
+
const kServiceId = Symbol.for('plt.runtime.service.id')
|
|
6
|
+
const kWorkerId = Symbol.for('plt.runtime.worker.id')
|
|
5
7
|
const kITC = Symbol.for('plt.runtime.itc')
|
|
8
|
+
const kLoggerDestination = Symbol.for('plt.runtime.loggerDestination')
|
|
9
|
+
const kLoggingPort = Symbol.for('plt.runtime.logginPort')
|
|
10
|
+
const kWorkerStatus = Symbol('plt.runtime.worker.status')
|
|
6
11
|
|
|
7
|
-
module.exports = { kConfig, kId, kITC }
|
|
12
|
+
module.exports = { kConfig, kId, kServiceId, kWorkerId, kITC, kLoggerDestination, kLoggingPort, kWorkerStatus }
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@platformatic/runtime",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.8.0-alpha.2",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -35,19 +35,18 @@
|
|
|
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/
|
|
39
|
-
"@platformatic/
|
|
40
|
-
"@platformatic/service": "2.
|
|
41
|
-
"@platformatic/node": "2.
|
|
42
|
-
"@platformatic/sql-
|
|
43
|
-
"@platformatic/sql-
|
|
38
|
+
"@platformatic/composer": "2.8.0-alpha.2",
|
|
39
|
+
"@platformatic/db": "2.8.0-alpha.2",
|
|
40
|
+
"@platformatic/service": "2.8.0-alpha.2",
|
|
41
|
+
"@platformatic/node": "2.8.0-alpha.2",
|
|
42
|
+
"@platformatic/sql-mapper": "2.8.0-alpha.2",
|
|
43
|
+
"@platformatic/sql-graphql": "2.8.0-alpha.2"
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
46
|
"@fastify/error": "^4.0.0",
|
|
47
47
|
"@fastify/websocket": "^11.0.0",
|
|
48
48
|
"@hapi/topo": "^6.0.2",
|
|
49
49
|
"@platformatic/http-metrics": "^0.2.1",
|
|
50
|
-
"@platformatic/undici-cache-memory": "^0.3.0",
|
|
51
50
|
"@watchable/unpromise": "^1.0.2",
|
|
52
51
|
"boring-name-generator": "^1.0.3",
|
|
53
52
|
"change-case-all": "^2.1.0",
|
|
@@ -69,20 +68,26 @@
|
|
|
69
68
|
"semgrator": "^0.3.0",
|
|
70
69
|
"tail-file-stream": "^0.2.0",
|
|
71
70
|
"thread-cpu-usage": "^0.2.0",
|
|
72
|
-
"undici": "
|
|
71
|
+
"undici": "^6.9.0",
|
|
73
72
|
"undici-thread-interceptor": "^0.7.0",
|
|
74
73
|
"ws": "^8.16.0",
|
|
75
|
-
"@platformatic/
|
|
76
|
-
"@platformatic/
|
|
77
|
-
"@platformatic/
|
|
78
|
-
"@platformatic/
|
|
79
|
-
"@platformatic/telemetry": "2.
|
|
80
|
-
"@platformatic/
|
|
81
|
-
"@platformatic/utils": "2.
|
|
74
|
+
"@platformatic/config": "2.8.0-alpha.2",
|
|
75
|
+
"@platformatic/generators": "2.8.0-alpha.2",
|
|
76
|
+
"@platformatic/basic": "2.8.0-alpha.2",
|
|
77
|
+
"@platformatic/itc": "2.8.0-alpha.2",
|
|
78
|
+
"@platformatic/telemetry": "2.8.0-alpha.2",
|
|
79
|
+
"@platformatic/ts-compiler": "2.8.0-alpha.2",
|
|
80
|
+
"@platformatic/utils": "2.8.0-alpha.2"
|
|
82
81
|
},
|
|
83
82
|
"scripts": {
|
|
84
|
-
"test": "npm run lint && borp --concurrency=1 --timeout=
|
|
85
|
-
"
|
|
83
|
+
"test": "npm run lint && borp --concurrency=1 --timeout=300000 && tsd",
|
|
84
|
+
"test:main": "borp --concurrency=1 --timeout=300000 test/*.test.js test/versions/*.test.js",
|
|
85
|
+
"test:api": "borp --concurrency=1 --timeout=300000 test/api/*.test.js test/management-api/*.test.js",
|
|
86
|
+
"test:cli": "borp --concurrency=1 --timeout=300000 test/cli/*.test.js test/cli/**/*.test.js",
|
|
87
|
+
"test:start": "borp --concurrency=1 --timeout=300000 test/start/*.test.js",
|
|
88
|
+
"test:multiple-workers": "borp --concurrency=1 --timeout=300000 test/multiple-workers/*.test.js",
|
|
89
|
+
"test:types": "tsd",
|
|
90
|
+
"coverage": "npm run lint && borp -X fixtures -X test -C --concurrency=1 --timeout=300000 && tsd",
|
|
86
91
|
"gen-schema": "node lib/schema.js > schema.json",
|
|
87
92
|
"gen-types": "json2ts > config.d.ts < schema.json",
|
|
88
93
|
"build": "pnpm run gen-schema && pnpm run gen-types",
|
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.8.0-alpha.2.json",
|
|
3
3
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
4
4
|
"type": "object",
|
|
5
5
|
"properties": {
|
|
@@ -91,10 +91,33 @@
|
|
|
91
91
|
},
|
|
92
92
|
"useHttp": {
|
|
93
93
|
"type": "boolean"
|
|
94
|
+
},
|
|
95
|
+
"workers": {
|
|
96
|
+
"anyOf": [
|
|
97
|
+
{
|
|
98
|
+
"type": "number",
|
|
99
|
+
"minimum": 1
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
"type": "string"
|
|
103
|
+
}
|
|
104
|
+
]
|
|
94
105
|
}
|
|
95
106
|
}
|
|
96
107
|
}
|
|
97
108
|
},
|
|
109
|
+
"workers": {
|
|
110
|
+
"anyOf": [
|
|
111
|
+
{
|
|
112
|
+
"type": "number",
|
|
113
|
+
"minimum": 1
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
"type": "string"
|
|
117
|
+
}
|
|
118
|
+
],
|
|
119
|
+
"default": 1
|
|
120
|
+
},
|
|
98
121
|
"web": {
|
|
99
122
|
"type": "array",
|
|
100
123
|
"items": {
|
|
@@ -129,6 +152,17 @@
|
|
|
129
152
|
},
|
|
130
153
|
"useHttp": {
|
|
131
154
|
"type": "boolean"
|
|
155
|
+
},
|
|
156
|
+
"workers": {
|
|
157
|
+
"anyOf": [
|
|
158
|
+
{
|
|
159
|
+
"type": "number",
|
|
160
|
+
"minimum": 1
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
"type": "string"
|
|
164
|
+
}
|
|
165
|
+
]
|
|
132
166
|
}
|
|
133
167
|
}
|
|
134
168
|
}
|
|
@@ -340,6 +374,41 @@
|
|
|
340
374
|
}
|
|
341
375
|
]
|
|
342
376
|
},
|
|
377
|
+
"gracefulShutdown": {
|
|
378
|
+
"type": "object",
|
|
379
|
+
"properties": {
|
|
380
|
+
"runtime": {
|
|
381
|
+
"anyOf": [
|
|
382
|
+
{
|
|
383
|
+
"type": "number",
|
|
384
|
+
"minimum": 1
|
|
385
|
+
},
|
|
386
|
+
{
|
|
387
|
+
"type": "string"
|
|
388
|
+
}
|
|
389
|
+
],
|
|
390
|
+
"default": 10000
|
|
391
|
+
},
|
|
392
|
+
"service": {
|
|
393
|
+
"anyOf": [
|
|
394
|
+
{
|
|
395
|
+
"type": "number",
|
|
396
|
+
"minimum": 1
|
|
397
|
+
},
|
|
398
|
+
{
|
|
399
|
+
"type": "string"
|
|
400
|
+
}
|
|
401
|
+
],
|
|
402
|
+
"default": 10000
|
|
403
|
+
}
|
|
404
|
+
},
|
|
405
|
+
"default": {},
|
|
406
|
+
"required": [
|
|
407
|
+
"runtime",
|
|
408
|
+
"service"
|
|
409
|
+
],
|
|
410
|
+
"additionalProperties": false
|
|
411
|
+
},
|
|
343
412
|
"undici": {
|
|
344
413
|
"type": "object",
|
|
345
414
|
"properties": {
|
|
@@ -382,35 +451,6 @@
|
|
|
382
451
|
}
|
|
383
452
|
}
|
|
384
453
|
},
|
|
385
|
-
"httpCache": {
|
|
386
|
-
"oneOf": [
|
|
387
|
-
{
|
|
388
|
-
"type": "boolean"
|
|
389
|
-
},
|
|
390
|
-
{
|
|
391
|
-
"type": "object",
|
|
392
|
-
"properties": {
|
|
393
|
-
"store": {
|
|
394
|
-
"type": "string"
|
|
395
|
-
},
|
|
396
|
-
"methods": {
|
|
397
|
-
"type": "array",
|
|
398
|
-
"items": {
|
|
399
|
-
"type": "string"
|
|
400
|
-
},
|
|
401
|
-
"default": [
|
|
402
|
-
"GET",
|
|
403
|
-
"HEAD"
|
|
404
|
-
],
|
|
405
|
-
"minItems": 1
|
|
406
|
-
},
|
|
407
|
-
"cacheTagsHeader": {
|
|
408
|
-
"type": "string"
|
|
409
|
-
}
|
|
410
|
-
}
|
|
411
|
-
}
|
|
412
|
-
]
|
|
413
|
-
},
|
|
414
454
|
"watch": {
|
|
415
455
|
"anyOf": [
|
|
416
456
|
{
|
package/lib/shared-http-cache.js
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const { join } = require('node:path')
|
|
4
|
-
const { createRequire } = require('node:module')
|
|
5
|
-
const MemoryCacheStore = require('@platformatic/undici-cache-memory')
|
|
6
|
-
|
|
7
|
-
function createSharedStore (projectDir, httpCacheConfig = {}) {
|
|
8
|
-
const runtimeRequire = createRequire(join(projectDir, 'file'))
|
|
9
|
-
|
|
10
|
-
const { store, ...storeConfig } = httpCacheConfig
|
|
11
|
-
const CacheStore = store ? runtimeRequire(store) : MemoryCacheStore
|
|
12
|
-
|
|
13
|
-
class SharedCacheStore extends CacheStore {
|
|
14
|
-
async getValue (req) {
|
|
15
|
-
const readStream = await this.createReadStream(req)
|
|
16
|
-
if (!readStream) return null
|
|
17
|
-
|
|
18
|
-
let payload = ''
|
|
19
|
-
for await (const chunk of readStream) {
|
|
20
|
-
payload += chunk
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const response = this.#sanitizeResponse(readStream.value)
|
|
24
|
-
return { response, payload }
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
setValue (req, opts, data) {
|
|
28
|
-
const writeStream = this.createWriteStream(req, opts)
|
|
29
|
-
writeStream.write(data)
|
|
30
|
-
writeStream.end()
|
|
31
|
-
return null
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
#sanitizeResponse (response) {
|
|
35
|
-
return {
|
|
36
|
-
...response,
|
|
37
|
-
rawHeaders: response.rawHeaders.map(header => header.toString())
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
return new SharedCacheStore(storeConfig)
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
module.exports = { createSharedStore }
|