@platformatic/runtime 3.0.0-alpha.5 → 3.0.0-alpha.8
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 +11 -7
- package/eslint.config.js +2 -4
- package/index.d.ts +11 -11
- package/index.js +35 -46
- package/lib/config.js +159 -102
- package/lib/errors.js +65 -99
- package/lib/generator.js +160 -164
- package/lib/logger.js +6 -8
- package/lib/management-api.js +91 -63
- package/lib/prom-server.js +10 -14
- package/lib/runtime.js +815 -747
- package/lib/scheduler.js +13 -15
- package/lib/schema.js +11 -8
- package/lib/shared-http-cache.js +5 -9
- package/lib/upgrade.js +5 -9
- package/lib/utils.js +6 -14
- package/lib/version.js +7 -0
- package/lib/versions/v1.36.0.js +2 -4
- package/lib/versions/v1.5.0.js +2 -4
- package/lib/versions/v2.0.0.js +3 -5
- package/lib/versions/v3.0.0.js +16 -0
- package/lib/worker/{app.js → controller.js} +68 -63
- package/lib/worker/http-cache.js +11 -14
- package/lib/worker/interceptors.js +14 -18
- package/lib/worker/itc.js +85 -79
- package/lib/worker/main.js +49 -55
- package/lib/worker/messaging.js +23 -27
- package/lib/worker/round-robin-map.js +23 -19
- package/lib/worker/shared-context.js +2 -6
- package/lib/worker/symbols.js +12 -29
- package/package.json +24 -23
- package/schema.json +281 -20
- package/lib/dependencies.js +0 -65
package/lib/scheduler.js
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
import { CronJob, validateCronExpression } from 'cron'
|
|
2
|
+
import { setTimeout } from 'node:timers/promises'
|
|
3
|
+
import { request } from 'undici'
|
|
2
4
|
|
|
3
|
-
|
|
4
|
-
const { setTimeout } = require('node:timers/promises')
|
|
5
|
-
const { request } = require('undici')
|
|
6
|
-
|
|
7
|
-
class SchedulerService {
|
|
5
|
+
export class SchedulerService {
|
|
8
6
|
constructor (schedulerConfig, dispatcher, logger) {
|
|
9
7
|
this.logger = logger
|
|
10
8
|
this.jobsConfig = []
|
|
@@ -49,7 +47,7 @@ class SchedulerService {
|
|
|
49
47
|
},
|
|
50
48
|
start: true,
|
|
51
49
|
timeZone: 'UTC',
|
|
52
|
-
waitForCompletion: true
|
|
50
|
+
waitForCompletion: true
|
|
53
51
|
})
|
|
54
52
|
|
|
55
53
|
this.cronJobs.push(cronJob)
|
|
@@ -71,7 +69,9 @@ class SchedulerService {
|
|
|
71
69
|
const delay = attempt > 0 ? 100 * Math.pow(2, attempt) : 0
|
|
72
70
|
|
|
73
71
|
if (delay > 0) {
|
|
74
|
-
this.logger.info(
|
|
72
|
+
this.logger.info(
|
|
73
|
+
`Retrying scheduler "${scheduler.name}" in ${delay}ms (attempt ${attempt + 1}/${scheduler.maxRetries})`
|
|
74
|
+
)
|
|
75
75
|
await setTimeout(delay)
|
|
76
76
|
}
|
|
77
77
|
const headers = {
|
|
@@ -98,7 +98,10 @@ class SchedulerService {
|
|
|
98
98
|
throw new Error(`HTTP error ${response.statusCode}`)
|
|
99
99
|
}
|
|
100
100
|
} catch (error) {
|
|
101
|
-
this.logger.error(
|
|
101
|
+
this.logger.error(
|
|
102
|
+
`Error executing scheduler "${scheduler.name}" (attempt ${attempt + 1}/${scheduler.maxRetries}):`,
|
|
103
|
+
error.message
|
|
104
|
+
)
|
|
102
105
|
attempt++
|
|
103
106
|
}
|
|
104
107
|
}
|
|
@@ -109,13 +112,8 @@ class SchedulerService {
|
|
|
109
112
|
}
|
|
110
113
|
}
|
|
111
114
|
|
|
112
|
-
|
|
115
|
+
export function startScheduler (config, interceptors, logger) {
|
|
113
116
|
const schedulerService = new SchedulerService(config, interceptors, logger)
|
|
114
117
|
schedulerService.start()
|
|
115
118
|
return schedulerService
|
|
116
119
|
}
|
|
117
|
-
|
|
118
|
-
module.exports = {
|
|
119
|
-
startScheduler,
|
|
120
|
-
SchedulerService
|
|
121
|
-
}
|
package/lib/schema.js
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
#! /usr/bin/env node
|
|
2
|
-
'use strict'
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
const pkg = require('../package.json')
|
|
3
|
+
import { schemaComponents } from '@platformatic/foundation'
|
|
4
|
+
import { version } from './version.js'
|
|
7
5
|
|
|
8
6
|
const runtimeLogger = {
|
|
9
7
|
...schemaComponents.runtimeProperties.logger,
|
|
@@ -19,17 +17,22 @@ const runtimeLogger = {
|
|
|
19
17
|
schemaComponents.runtimeProperties.logger = runtimeLogger
|
|
20
18
|
|
|
21
19
|
const platformaticRuntimeSchema = {
|
|
22
|
-
$id: `https://schemas.platformatic.dev/@platformatic/runtime/${
|
|
20
|
+
$id: `https://schemas.platformatic.dev/@platformatic/runtime/${version}.json`,
|
|
23
21
|
$schema: 'http://json-schema.org/draft-07/schema#',
|
|
24
22
|
title: 'Platformatic Runtime Config',
|
|
25
23
|
type: 'object',
|
|
26
24
|
properties: schemaComponents.runtimeProperties,
|
|
27
|
-
anyOf: [
|
|
25
|
+
anyOf: [
|
|
26
|
+
{ required: ['autoload'] },
|
|
27
|
+
{ required: ['applications'] },
|
|
28
|
+
{ required: ['services'] },
|
|
29
|
+
{ required: ['web'] }
|
|
30
|
+
],
|
|
28
31
|
additionalProperties: false
|
|
29
32
|
}
|
|
30
33
|
|
|
31
|
-
|
|
34
|
+
export const schema = platformaticRuntimeSchema
|
|
32
35
|
|
|
33
|
-
if (
|
|
36
|
+
if (import.meta.main) {
|
|
34
37
|
console.log(JSON.stringify(platformaticRuntimeSchema, null, 2))
|
|
35
38
|
}
|
package/lib/shared-http-cache.js
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
import { loadModule } from '@platformatic/foundation'
|
|
2
|
+
import MemoryCacheStore from '@platformatic/undici-cache-memory'
|
|
3
|
+
import { createRequire } from 'node:module'
|
|
4
|
+
import { join } from 'node:path'
|
|
2
5
|
|
|
3
|
-
|
|
4
|
-
const { loadModule } = require('@platformatic/foundation')
|
|
5
|
-
const MemoryCacheStore = require('@platformatic/undici-cache-memory')
|
|
6
|
-
const { createRequire } = require('node:module')
|
|
7
|
-
|
|
8
|
-
async function createSharedStore (projectDir, httpCacheConfig = {}) {
|
|
6
|
+
export async function createSharedStore (projectDir, httpCacheConfig = {}) {
|
|
9
7
|
const runtimeRequire = createRequire(join(projectDir, 'file'))
|
|
10
8
|
|
|
11
9
|
const { store, ...storeConfig } = httpCacheConfig
|
|
@@ -43,5 +41,3 @@ async function createSharedStore (projectDir, httpCacheConfig = {}) {
|
|
|
43
41
|
|
|
44
42
|
return new SharedCacheStore(storeConfig)
|
|
45
43
|
}
|
|
46
|
-
|
|
47
|
-
module.exports = { createSharedStore }
|
package/lib/upgrade.js
CHANGED
|
@@ -1,13 +1,11 @@
|
|
|
1
|
-
|
|
1
|
+
import { abstractLogger } from '@platformatic/foundation'
|
|
2
|
+
import { join } from 'node:path'
|
|
3
|
+
import { semgrator } from 'semgrator'
|
|
2
4
|
|
|
3
|
-
|
|
4
|
-
const { join } = require('node:path')
|
|
5
|
-
const { semgrator } = require('semgrator')
|
|
6
|
-
|
|
7
|
-
async function upgrade (logger, config, version) {
|
|
5
|
+
export async function upgrade (logger, config, version) {
|
|
8
6
|
const iterator = semgrator({
|
|
9
7
|
version,
|
|
10
|
-
path: join(
|
|
8
|
+
path: join(import.meta.dirname, 'versions'),
|
|
11
9
|
input: config,
|
|
12
10
|
logger: logger?.child({ name: '@platformatic/runtime' }) ?? abstractLogger
|
|
13
11
|
})
|
|
@@ -20,5 +18,3 @@ async function upgrade (logger, config, version) {
|
|
|
20
18
|
|
|
21
19
|
return result
|
|
22
20
|
}
|
|
23
|
-
|
|
24
|
-
module.exports = { upgrade }
|
package/lib/utils.js
CHANGED
|
@@ -1,27 +1,19 @@
|
|
|
1
|
-
|
|
1
|
+
import { createHash } from 'node:crypto'
|
|
2
|
+
import { tmpdir } from 'node:os'
|
|
3
|
+
import { join } from 'node:path'
|
|
2
4
|
|
|
3
|
-
|
|
4
|
-
const { tmpdir } = require('node:os')
|
|
5
|
-
const { join } = require('node:path')
|
|
6
|
-
|
|
7
|
-
function getArrayDifference (a, b) {
|
|
5
|
+
export function getArrayDifference (a, b) {
|
|
8
6
|
return a.filter(element => {
|
|
9
7
|
return !b.includes(element)
|
|
10
8
|
})
|
|
11
9
|
}
|
|
12
10
|
|
|
13
|
-
function
|
|
11
|
+
export function getApplicationUrl (id) {
|
|
14
12
|
return `http://${id}.plt.local`
|
|
15
13
|
}
|
|
16
14
|
|
|
17
|
-
function getRuntimeTmpDir (runtimeDir) {
|
|
15
|
+
export function getRuntimeTmpDir (runtimeDir) {
|
|
18
16
|
const platformaticTmpDir = join(tmpdir(), 'platformatic', 'applications')
|
|
19
17
|
const runtimeDirHash = createHash('md5').update(runtimeDir).digest('hex')
|
|
20
18
|
return join(platformaticTmpDir, runtimeDirHash)
|
|
21
19
|
}
|
|
22
|
-
|
|
23
|
-
module.exports = {
|
|
24
|
-
getArrayDifference,
|
|
25
|
-
getRuntimeTmpDir,
|
|
26
|
-
getServiceUrl
|
|
27
|
-
}
|
package/lib/version.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs'
|
|
2
|
+
import { resolve } from 'node:path'
|
|
3
|
+
|
|
4
|
+
const packageJson = JSON.parse(readFileSync(resolve(import.meta.dirname, '../package.json'), 'utf-8'))
|
|
5
|
+
|
|
6
|
+
export const name = packageJson.name
|
|
7
|
+
export const version = packageJson.version
|
package/lib/versions/v1.36.0.js
CHANGED
package/lib/versions/v1.5.0.js
CHANGED
package/lib/versions/v2.0.0.js
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
import { version } from '../version.js'
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
module.exports = {
|
|
3
|
+
export default {
|
|
6
4
|
version: '1.99.0', // This is to account alpha versions as well
|
|
7
5
|
up: function (config) {
|
|
8
6
|
if (config.restartOnError === undefined) {
|
|
@@ -16,7 +14,7 @@ module.exports = {
|
|
|
16
14
|
|
|
17
15
|
delete config.allowCycles
|
|
18
16
|
|
|
19
|
-
config.$schema = `https://schemas.platformatic.dev/@platformatic/runtime/${
|
|
17
|
+
config.$schema = `https://schemas.platformatic.dev/@platformatic/runtime/${version}.json`
|
|
20
18
|
|
|
21
19
|
if (config.server?.logger) {
|
|
22
20
|
config.logger = config.server.logger
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
version: '2.99.0',
|
|
3
|
+
up (config) {
|
|
4
|
+
if (typeof config.gracefulShutdown?.service === 'number') {
|
|
5
|
+
config.gracefulShutdown.application = config.gracefulShutdown.service
|
|
6
|
+
delete config.gracefulShutdown.service
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
if (typeof config.serviceTimeout === 'number') {
|
|
10
|
+
config.applicationTimeout = config.serviceTimeout
|
|
11
|
+
delete config.serviceTimeout
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return config
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -1,35 +1,30 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const { existsSync } = require('node:fs')
|
|
4
|
-
const { EventEmitter } = require('node:events')
|
|
5
|
-
const { resolve } = require('node:path')
|
|
6
|
-
const {
|
|
7
|
-
performance: { eventLoopUtilization }
|
|
8
|
-
} = require('node:perf_hooks')
|
|
9
|
-
const { workerData } = require('node:worker_threads')
|
|
10
|
-
const {
|
|
1
|
+
import {
|
|
2
|
+
ensureLoggableError,
|
|
11
3
|
FileWatcher,
|
|
4
|
+
kHandledError,
|
|
12
5
|
listRecognizedConfigurationFiles,
|
|
13
|
-
loadConfigurationModule,
|
|
14
6
|
loadConfiguration,
|
|
15
|
-
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
7
|
+
loadConfigurationModule
|
|
8
|
+
} from '@platformatic/foundation'
|
|
9
|
+
import debounce from 'debounce'
|
|
10
|
+
import { EventEmitter } from 'node:events'
|
|
11
|
+
import { existsSync } from 'node:fs'
|
|
12
|
+
import { resolve } from 'node:path'
|
|
13
|
+
import { getActiveResourcesInfo } from 'node:process'
|
|
14
|
+
import { workerData } from 'node:worker_threads'
|
|
15
|
+
import { getGlobalDispatcher, setGlobalDispatcher } from 'undici'
|
|
16
|
+
import { ApplicationAlreadyStartedError, RuntimeNotStartedError } from '../errors.js'
|
|
17
|
+
import { getApplicationUrl } from '../utils.js'
|
|
18
|
+
|
|
19
|
+
function fetchApplicationUrl (application, key) {
|
|
20
|
+
if (!key.endsWith('_URL') || !application.id) {
|
|
26
21
|
return null
|
|
27
22
|
}
|
|
28
23
|
|
|
29
|
-
return
|
|
24
|
+
return getApplicationUrl(application.id)
|
|
30
25
|
}
|
|
31
26
|
|
|
32
|
-
class
|
|
27
|
+
export class Controller extends EventEmitter {
|
|
33
28
|
#starting
|
|
34
29
|
#started
|
|
35
30
|
#listening
|
|
@@ -51,20 +46,22 @@ class PlatformaticApp extends EventEmitter {
|
|
|
51
46
|
) {
|
|
52
47
|
super()
|
|
53
48
|
this.appConfig = appConfig
|
|
54
|
-
this.
|
|
49
|
+
this.applicationId = this.appConfig.id
|
|
55
50
|
this.workerId = workerId
|
|
56
51
|
this.#watch = watch
|
|
57
52
|
this.#starting = false
|
|
58
53
|
this.#started = false
|
|
59
54
|
this.#listening = false
|
|
60
|
-
this.
|
|
55
|
+
this.capability = null
|
|
61
56
|
this.#fileWatcher = null
|
|
62
|
-
this.#lastELU = eventLoopUtilization()
|
|
57
|
+
this.#lastELU = performance.eventLoopUtilization()
|
|
63
58
|
|
|
64
59
|
this.#context = {
|
|
65
|
-
|
|
60
|
+
controller: this,
|
|
61
|
+
applicationId: this.applicationId,
|
|
66
62
|
workerId: this.workerId,
|
|
67
63
|
directory: this.appConfig.path,
|
|
64
|
+
dependencies: this.appConfig.dependencies,
|
|
68
65
|
isEntrypoint: this.appConfig.entrypoint,
|
|
69
66
|
isProduction: this.appConfig.isProduction,
|
|
70
67
|
telemetryConfig,
|
|
@@ -73,8 +70,7 @@ class PlatformaticApp extends EventEmitter {
|
|
|
73
70
|
serverConfig,
|
|
74
71
|
worker: workerData?.worker,
|
|
75
72
|
hasManagementApi: !!hasManagementApi,
|
|
76
|
-
|
|
77
|
-
fetchServiceUrl: fetchServiceUrl.bind(null, appConfig)
|
|
73
|
+
fetchApplicationUrl: fetchApplicationUrl.bind(null, appConfig)
|
|
78
74
|
}
|
|
79
75
|
}
|
|
80
76
|
|
|
@@ -86,15 +82,12 @@ class PlatformaticApp extends EventEmitter {
|
|
|
86
82
|
|
|
87
83
|
async updateContext (context) {
|
|
88
84
|
this.#context = { ...this.#context, ...context }
|
|
89
|
-
if (this.
|
|
90
|
-
await this.
|
|
85
|
+
if (this.capability) {
|
|
86
|
+
await this.capability.updateContext(context)
|
|
91
87
|
}
|
|
92
88
|
}
|
|
93
89
|
|
|
94
|
-
|
|
95
|
-
return this.stackable.getBootstrapDependencies?.() ?? []
|
|
96
|
-
}
|
|
97
|
-
|
|
90
|
+
// Note: capability's init() is executed within start
|
|
98
91
|
async init () {
|
|
99
92
|
try {
|
|
100
93
|
const appConfig = this.appConfig
|
|
@@ -116,25 +109,25 @@ class PlatformaticApp extends EventEmitter {
|
|
|
116
109
|
if (appConfig.config) {
|
|
117
110
|
// Parse the configuration file the first time to obtain the schema
|
|
118
111
|
const unvalidatedConfig = await loadConfiguration(appConfig.config, null, {
|
|
119
|
-
onMissingEnv: this.#context.
|
|
112
|
+
onMissingEnv: this.#context.fetchApplicationUrl
|
|
120
113
|
})
|
|
121
114
|
const pkg = await loadConfigurationModule(appConfig.path, unvalidatedConfig)
|
|
122
|
-
this.
|
|
115
|
+
this.capability = await pkg.create(appConfig.path, appConfig.config, this.#context)
|
|
123
116
|
// We could not find a configuration file, we use the bundle @platformatic/basic with the runtime to load it
|
|
124
117
|
} else {
|
|
125
|
-
const pkg = await loadConfigurationModule(resolve(
|
|
126
|
-
this.
|
|
118
|
+
const pkg = await loadConfigurationModule(resolve(import.meta.dirname, '../..'), {}, '@platformatic/basic')
|
|
119
|
+
this.capability = await pkg.create(appConfig.path, {}, this.#context)
|
|
127
120
|
}
|
|
128
121
|
|
|
129
122
|
this.#updateDispatcher()
|
|
130
123
|
} catch (err) {
|
|
131
124
|
if (err.validationErrors) {
|
|
132
125
|
globalThis.platformatic.logger.error(
|
|
133
|
-
{ err: ensureLoggableError(err
|
|
126
|
+
{ err: ensureLoggableError(err) },
|
|
134
127
|
'The application threw a validation error.'
|
|
135
128
|
)
|
|
136
129
|
|
|
137
|
-
|
|
130
|
+
throw err
|
|
138
131
|
} else {
|
|
139
132
|
this.#logAndThrow(err)
|
|
140
133
|
}
|
|
@@ -143,24 +136,31 @@ class PlatformaticApp extends EventEmitter {
|
|
|
143
136
|
|
|
144
137
|
async start () {
|
|
145
138
|
if (this.#starting || this.#started) {
|
|
146
|
-
throw new
|
|
139
|
+
throw new ApplicationAlreadyStartedError()
|
|
147
140
|
}
|
|
148
141
|
|
|
149
142
|
this.#starting = true
|
|
150
143
|
|
|
151
144
|
try {
|
|
152
|
-
await this.
|
|
145
|
+
await this.capability.init?.()
|
|
146
|
+
this.emit('init')
|
|
153
147
|
} catch (err) {
|
|
154
148
|
this.#logAndThrow(err)
|
|
155
149
|
}
|
|
156
150
|
|
|
151
|
+
this.emit('starting')
|
|
152
|
+
|
|
153
|
+
if (this.capability.status === 'stopped') {
|
|
154
|
+
return
|
|
155
|
+
}
|
|
156
|
+
|
|
157
157
|
if (this.#watch) {
|
|
158
|
-
const watchConfig = await this.
|
|
158
|
+
const watchConfig = await this.capability.getWatchConfig()
|
|
159
159
|
|
|
160
160
|
if (watchConfig.enabled !== false) {
|
|
161
161
|
/* c8 ignore next 4 */
|
|
162
162
|
this.#debouncedRestart = debounce(() => {
|
|
163
|
-
this.
|
|
163
|
+
this.capability.log({ message: 'files changed', level: 'debug' })
|
|
164
164
|
this.emit('changed')
|
|
165
165
|
}, 100) // debounce restart for 100ms
|
|
166
166
|
|
|
@@ -171,32 +171,34 @@ class PlatformaticApp extends EventEmitter {
|
|
|
171
171
|
const listen = !!this.appConfig.useHttp
|
|
172
172
|
|
|
173
173
|
try {
|
|
174
|
-
await this.
|
|
174
|
+
await this.capability.start({ listen })
|
|
175
175
|
this.#listening = listen
|
|
176
176
|
/* c8 ignore next 5 */
|
|
177
177
|
} catch (err) {
|
|
178
|
-
this.
|
|
178
|
+
this.capability.log({ message: err.message, level: 'debug' })
|
|
179
179
|
this.#starting = false
|
|
180
180
|
throw err
|
|
181
181
|
}
|
|
182
182
|
|
|
183
183
|
this.#started = true
|
|
184
184
|
this.#starting = false
|
|
185
|
-
this.emit('
|
|
185
|
+
this.emit('started')
|
|
186
186
|
}
|
|
187
187
|
|
|
188
|
-
async stop (force = false) {
|
|
188
|
+
async stop (force = false, dependents = []) {
|
|
189
189
|
if (!force && (!this.#started || this.#starting)) {
|
|
190
|
-
throw new
|
|
190
|
+
throw new RuntimeNotStartedError()
|
|
191
191
|
}
|
|
192
192
|
|
|
193
|
+
this.emit('stopping')
|
|
193
194
|
await this.#stopFileWatching()
|
|
194
|
-
await this.
|
|
195
|
+
await this.capability.waitForDependentsStop(dependents)
|
|
196
|
+
await this.capability.stop()
|
|
195
197
|
|
|
196
198
|
this.#started = false
|
|
197
199
|
this.#starting = false
|
|
198
200
|
this.#listening = false
|
|
199
|
-
this.emit('
|
|
201
|
+
this.emit('stopped')
|
|
200
202
|
}
|
|
201
203
|
|
|
202
204
|
async listen () {
|
|
@@ -205,7 +207,7 @@ class PlatformaticApp extends EventEmitter {
|
|
|
205
207
|
return
|
|
206
208
|
}
|
|
207
209
|
|
|
208
|
-
await this.
|
|
210
|
+
await this.capability.start({ listen: true })
|
|
209
211
|
}
|
|
210
212
|
|
|
211
213
|
async getMetrics ({ format }) {
|
|
@@ -221,12 +223,13 @@ class PlatformaticApp extends EventEmitter {
|
|
|
221
223
|
globalThis.platformatic.onHttpStatsSize(url, size || 0)
|
|
222
224
|
}
|
|
223
225
|
}
|
|
224
|
-
|
|
226
|
+
globalThis.platformatic.onActiveResourcesEventLoop(getActiveResourcesInfo().length)
|
|
227
|
+
return this.capability.getMetrics({ format })
|
|
225
228
|
}
|
|
226
229
|
|
|
227
230
|
async getHealth () {
|
|
228
|
-
const currentELU = eventLoopUtilization()
|
|
229
|
-
const elu = eventLoopUtilization(currentELU, this.#lastELU).utilization
|
|
231
|
+
const currentELU = performance.eventLoopUtilization()
|
|
232
|
+
const elu = performance.eventLoopUtilization(currentELU, this.#lastELU).utilization
|
|
230
233
|
this.#lastELU = currentELU
|
|
231
234
|
|
|
232
235
|
const { heapUsed, heapTotal } = process.memoryUsage()
|
|
@@ -253,7 +256,7 @@ class PlatformaticApp extends EventEmitter {
|
|
|
253
256
|
fileWatcher.on('update', this.#debouncedRestart)
|
|
254
257
|
|
|
255
258
|
fileWatcher.startWatching()
|
|
256
|
-
this.
|
|
259
|
+
this.capability.log({ message: 'start watching files', level: 'debug' })
|
|
257
260
|
this.#fileWatcher = fileWatcher
|
|
258
261
|
}
|
|
259
262
|
|
|
@@ -261,20 +264,24 @@ class PlatformaticApp extends EventEmitter {
|
|
|
261
264
|
const watcher = this.#fileWatcher
|
|
262
265
|
|
|
263
266
|
if (watcher) {
|
|
264
|
-
this.
|
|
267
|
+
this.capability.log({ message: 'stop watching files', level: 'debug' })
|
|
265
268
|
await watcher.stopWatching()
|
|
266
269
|
this.#fileWatcher = null
|
|
267
270
|
}
|
|
268
271
|
}
|
|
269
272
|
|
|
270
273
|
#logAndThrow (err) {
|
|
271
|
-
globalThis.platformatic.logger.error(
|
|
274
|
+
globalThis.platformatic.logger.error(
|
|
275
|
+
{ err: ensureLoggableError(err) },
|
|
276
|
+
err[kHandledError] ? err.message : 'The application threw an error.'
|
|
277
|
+
)
|
|
278
|
+
|
|
272
279
|
throw err
|
|
273
280
|
}
|
|
274
281
|
|
|
275
282
|
#updateDispatcher () {
|
|
276
283
|
const telemetryConfig = this.#context.telemetryConfig
|
|
277
|
-
const telemetryId = telemetryConfig?.
|
|
284
|
+
const telemetryId = telemetryConfig?.applicationName
|
|
278
285
|
|
|
279
286
|
const interceptor = dispatch => {
|
|
280
287
|
return function InterceptedDispatch (opts, handler) {
|
|
@@ -293,5 +300,3 @@ class PlatformaticApp extends EventEmitter {
|
|
|
293
300
|
setGlobalDispatcher(dispatcher)
|
|
294
301
|
}
|
|
295
302
|
}
|
|
296
|
-
|
|
297
|
-
module.exports = { PlatformaticApp }
|
package/lib/worker/http-cache.js
CHANGED
|
@@ -1,16 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const { interceptors } = require('undici')
|
|
6
|
-
const { kITC } = require('./symbols')
|
|
1
|
+
import { randomUUID } from 'node:crypto'
|
|
2
|
+
import { Readable, Writable } from 'node:stream'
|
|
3
|
+
import { interceptors } from 'undici'
|
|
4
|
+
import { kITC } from './symbols.js'
|
|
7
5
|
|
|
8
6
|
const kCacheIdHeader = Symbol('cacheIdHeader')
|
|
9
7
|
const CACHE_ID_HEADER = 'x-plt-http-cache-id'
|
|
10
8
|
|
|
11
9
|
const noop = () => {}
|
|
12
10
|
|
|
13
|
-
class RemoteCacheStore {
|
|
11
|
+
export class RemoteCacheStore {
|
|
14
12
|
#onRequest
|
|
15
13
|
#onCacheHit
|
|
16
14
|
#onCacheMiss
|
|
@@ -89,9 +87,10 @@ class RemoteCacheStore {
|
|
|
89
87
|
} else {
|
|
90
88
|
payload = Buffer.concat(acc)
|
|
91
89
|
}
|
|
92
|
-
itc
|
|
90
|
+
itc
|
|
91
|
+
.send('setHttpCacheValue', { request: key, response: value, payload })
|
|
93
92
|
.then(() => callback())
|
|
94
|
-
.catch(
|
|
93
|
+
.catch(err => callback(err))
|
|
95
94
|
}
|
|
96
95
|
})
|
|
97
96
|
}
|
|
@@ -116,14 +115,14 @@ class RemoteCacheStore {
|
|
|
116
115
|
}
|
|
117
116
|
}
|
|
118
117
|
|
|
119
|
-
|
|
118
|
+
export function httpCacheInterceptor (interceptorOpts) {
|
|
120
119
|
const originalInterceptor = interceptors.cache(interceptorOpts)
|
|
121
120
|
|
|
122
121
|
// AsyncLocalStorage that contains a client http request span
|
|
123
|
-
// Exists only when the nodejs
|
|
122
|
+
// Exists only when the nodejs capability telemetry is enabled
|
|
124
123
|
const clientSpansAls = globalThis.platformatic.clientSpansAls
|
|
125
124
|
|
|
126
|
-
return
|
|
125
|
+
return originalDispatch => {
|
|
127
126
|
const dispatch = (opts, handler) => {
|
|
128
127
|
const originOnResponseStart = handler.onResponseStart.bind(handler)
|
|
129
128
|
handler.onResponseStart = (ac, statusCode, headers, statusMessage) => {
|
|
@@ -170,5 +169,3 @@ const httpCacheInterceptor = (interceptorOpts) => {
|
|
|
170
169
|
}
|
|
171
170
|
}
|
|
172
171
|
}
|
|
173
|
-
|
|
174
|
-
module.exports = { RemoteCacheStore, httpCacheInterceptor }
|
|
@@ -1,16 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
async function setDispatcher (runtimeConfig) {
|
|
1
|
+
import { createTelemetryThreadInterceptorHooks } from '@platformatic/telemetry'
|
|
2
|
+
import { createRequire } from 'node:module'
|
|
3
|
+
import { join } from 'node:path'
|
|
4
|
+
import { pathToFileURL } from 'node:url'
|
|
5
|
+
import { parentPort, workerData } from 'node:worker_threads'
|
|
6
|
+
import { Agent, Client, Pool, setGlobalDispatcher } from 'undici'
|
|
7
|
+
import { wire } from 'undici-thread-interceptor'
|
|
8
|
+
import { RemoteCacheStore, httpCacheInterceptor } from './http-cache.js'
|
|
9
|
+
import { kInterceptors } from './symbols.js'
|
|
10
|
+
|
|
11
|
+
export async function setDispatcher (runtimeConfig) {
|
|
14
12
|
const threadDispatcher = createThreadInterceptor(runtimeConfig)
|
|
15
13
|
const threadInterceptor = threadDispatcher.interceptor
|
|
16
14
|
|
|
@@ -34,7 +32,7 @@ async function setDispatcher (runtimeConfig) {
|
|
|
34
32
|
return { threadDispatcher }
|
|
35
33
|
}
|
|
36
34
|
|
|
37
|
-
async function updateUndiciInterceptors (undiciConfig) {
|
|
35
|
+
export async function updateUndiciInterceptors (undiciConfig) {
|
|
38
36
|
const updatableInterceptors = globalThis[kInterceptors]
|
|
39
37
|
if (!updatableInterceptors) return
|
|
40
38
|
|
|
@@ -172,8 +170,8 @@ function createThreadInterceptor (runtimeConfig) {
|
|
|
172
170
|
// with requests for a domain that's never going to exist.
|
|
173
171
|
domain: '.plt.local',
|
|
174
172
|
port: parentPort,
|
|
175
|
-
timeout: runtimeConfig.
|
|
176
|
-
...telemetryHooks
|
|
173
|
+
timeout: runtimeConfig.applicationTimeout,
|
|
174
|
+
...telemetryHooks
|
|
177
175
|
})
|
|
178
176
|
return threadDispatcher
|
|
179
177
|
}
|
|
@@ -197,5 +195,3 @@ function createHttpCacheInterceptor (runtimeConfig) {
|
|
|
197
195
|
})
|
|
198
196
|
return cacheInterceptor
|
|
199
197
|
}
|
|
200
|
-
|
|
201
|
-
module.exports = { setDispatcher, updateUndiciInterceptors }
|