@platformatic/runtime 2.0.0-alpha.2 → 2.0.0-alpha.4
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 +285 -0
- package/eslint.config.js +8 -0
- package/fixtures/botched-start/platformatic.runtime.json +1 -1
- package/fixtures/botched-start/services/a/platformatic.service.json +1 -1
- package/fixtures/composerApp/platformatic.composer.json +1 -1
- package/fixtures/configs/invalid-autoload-with-services.json +1 -1
- package/fixtures/configs/invalid-entrypoint.json +1 -1
- package/fixtures/configs/invalid-schema-type.config.json +1 -1
- package/fixtures/configs/missing-property.config.json +1 -1
- package/fixtures/configs/missing-service-config.json +1 -1
- package/fixtures/configs/monorepo-composer-no-autoload.json +2 -2
- package/fixtures/configs/monorepo-composer.json +2 -2
- package/fixtures/configs/monorepo-create-cycle.json +2 -2
- package/fixtures/configs/monorepo-missing-dependencies.json +2 -2
- package/fixtures/configs/monorepo-no-cycles.json +2 -2
- package/fixtures/configs/monorepo-openapi.json +2 -2
- package/fixtures/configs/{monorepo-hotreload-env.json → monorepo-watch-env.json} +2 -2
- package/fixtures/configs/monorepo-watch-single.json +12 -0
- package/fixtures/configs/monorepo-watch.json +26 -9
- package/fixtures/configs/monorepo-with-dependencies.json +2 -2
- package/fixtures/configs/monorepo-with-management-api-without-metrics.json +21 -0
- package/fixtures/configs/monorepo-with-management-api.json +2 -2
- package/fixtures/configs/{monorepo-hotreload.json → monorepo-with-metrics.json} +5 -4
- package/fixtures/configs/monorepo.json +2 -2
- package/fixtures/configs/no-services.config.json +1 -1
- package/fixtures/configs/no-sources.config.json +1 -1
- package/fixtures/configs/service-throws-on-start.json +1 -1
- package/fixtures/configs/service-with-env-port.json +2 -2
- package/fixtures/configs/service-with-stdio.json +12 -0
- package/fixtures/configs/{hotreload.json → watch.json} +2 -2
- package/fixtures/crash-on-bootstrap/platformatic.runtime.json +15 -0
- package/fixtures/crash-on-bootstrap/services/service-1/platformatic.service.json +14 -0
- package/fixtures/crash-on-bootstrap/services/service-1/plugin.js +5 -0
- package/fixtures/crash-on-bootstrap/services/service-2/platformatic.service.json +14 -0
- package/fixtures/crash-on-bootstrap/services/service-2/plugin.js +5 -0
- package/fixtures/dbApp/platformatic.db.json +1 -1
- package/fixtures/dbAppNoName/platformatic.db.json +1 -1
- package/fixtures/dbAppNoPackageJson/platformatic.db.json +1 -1
- package/fixtures/dbAppWithMigrationError/platformatic.db.json +1 -1
- package/fixtures/do-not-reload-dependencies/platformatic.service.json +1 -1
- package/fixtures/do-not-restart-on-crash/platformatic.runtime.json +3 -2
- package/fixtures/do-not-restart-on-crash/services/a/platformatic.service.json +1 -1
- package/fixtures/express/platformatic.runtime.json +1 -1
- package/fixtures/express/services/a/platformatic.service.json +1 -1
- package/fixtures/express/services/b/platformatic.service.json +1 -1
- package/fixtures/external-client/platformatic.service.json +1 -1
- package/fixtures/interceptors/idp.js +2 -2
- package/fixtures/interceptors/platformatic.runtime.json +1 -1
- package/fixtures/interceptors/services/a/platformatic.service.json +1 -1
- package/fixtures/interceptors-2/platformatic.runtime.json +1 -1
- package/fixtures/interceptors-2/services/a/platformatic.service.json +1 -1
- package/fixtures/leven/platformatic.runtime.json +2 -2
- package/fixtures/leven/services/deeply-spittle/platformatic.service.json +1 -1
- package/fixtures/leven/services/rainy-empire/platformatic.composer.json +1 -1
- package/fixtures/management-api/platformatic.json +3 -3
- package/fixtures/management-api/services/service-1/platformatic.json +1 -1
- package/fixtures/management-api/services/service-1/plugin.js +4 -3
- package/fixtures/management-api/services/service-2/platformatic.json +1 -1
- package/fixtures/management-api/services/service-db/platformatic.db.json +1 -1
- package/fixtures/management-api-custom-labels/platformatic.json +2 -2
- package/fixtures/management-api-custom-labels/services/service-1/platformatic.json +1 -1
- package/fixtures/management-api-custom-labels/services/service-1/plugin.js +4 -3
- package/fixtures/management-api-custom-labels/services/service-2/platformatic.json +1 -1
- package/fixtures/management-api-custom-labels/services/service-db/platformatic.db.json +1 -1
- package/fixtures/management-api-without-metrics/platformatic.json +3 -2
- package/fixtures/management-api-without-metrics/services/service-1/platformatic.json +1 -1
- package/fixtures/monorepo/composerApp/platformatic.composer.json +1 -1
- package/fixtures/monorepo/dbApp/platformatic.db.json +1 -1
- package/fixtures/monorepo/serviceApp/platformatic.service.json +3 -2
- package/fixtures/monorepo/serviceApp/with-logger/with-logger.cjs +2 -2
- package/fixtures/monorepo/serviceApp/with-logger/with-logger.d.ts +7 -7
- package/fixtures/monorepo/serviceAppWithLogger/platformatic.service.json +1 -1
- package/fixtures/monorepo/serviceAppWithLogger/plugin.js +12 -0
- package/fixtures/monorepo/serviceAppWithMultiplePlugins/platformatic.service.json +3 -2
- package/fixtures/monorepo-missing-dependencies/composer/platformatic.json +1 -1
- package/fixtures/monorepo-openapi/serviceAppWithoutOpenapi/platformatic.service.json +1 -1
- package/fixtures/monorepo-watch/service1/platformatic.service.json +1 -1
- package/fixtures/monorepo-with-dependencies/main/platformatic.json +1 -1
- package/fixtures/monorepo-with-dependencies/service-1/platformatic.json +1 -1
- package/fixtures/monorepo-with-dependencies/service-2/platformatic.json +1 -1
- package/fixtures/no-env.service.json +1 -1
- package/fixtures/preload/platformatic.runtime.json +1 -1
- package/fixtures/preload/services/a/platformatic.service.json +1 -1
- package/fixtures/prom-server/platformatic.json +2 -2
- package/fixtures/prom-server/services/service-1/platformatic.json +1 -1
- package/fixtures/prom-server/services/service-2/platformatic.json +1 -1
- package/fixtures/restart-on-crash/platformatic.runtime.json +1 -1
- package/fixtures/restart-on-crash/services/a/platformatic.service.json +1 -1
- package/fixtures/sample-runtime/package.json +1 -1
- package/fixtures/sample-runtime/platformatic.json +2 -2
- package/fixtures/sample-runtime/services/rival/package.json +1 -1
- package/fixtures/sample-runtime/services/rival/platformatic.json +1 -1
- package/fixtures/sample-runtime-with-2-services/package.json +1 -1
- package/fixtures/sample-runtime-with-2-services/platformatic.json +2 -2
- package/fixtures/sample-runtime-with-2-services/services/foobar/package.json +1 -1
- package/fixtures/sample-runtime-with-2-services/services/foobar/platformatic.json +1 -1
- package/fixtures/sample-runtime-with-2-services/services/rival/package.json +1 -1
- package/fixtures/sample-runtime-with-2-services/services/rival/platformatic.json +1 -1
- package/fixtures/server/logger-transport/platformatic.runtime.json +2 -2
- package/fixtures/server/logger-transport/services/echo/platformatic.service.json +1 -1
- package/fixtures/server/overrides-service/platformatic.runtime.json +2 -2
- package/fixtures/server/overrides-service/services/echo/platformatic.service.json +1 -1
- package/fixtures/server/runtime-server/platformatic.runtime.json +2 -2
- package/fixtures/server/runtime-server/services/echo/platformatic.service.json +1 -1
- package/fixtures/serviceAppThrowsOnStart/platformatic.service.json +1 -1
- package/fixtures/stackables/node_modules/foo/foo.js +2 -1
- package/fixtures/start-command-in-runtime.js +1 -1
- package/fixtures/stdio/platformatic.service.json +6 -0
- package/fixtures/stdio/plugin.js +24 -0
- package/fixtures/telemetry/platformatic.runtime.json +2 -2
- package/fixtures/telemetry/services/echo/platformatic.service.json +1 -1
- package/fixtures/telemetry/services/echo/routes/span.js +16 -2
- package/fixtures/telemetry/services/service-1/platformatic.service.json +19 -0
- package/fixtures/telemetry/services/service-1/routes/echo.js +7 -0
- package/fixtures/typescript/platformatic.runtime.json +2 -2
- package/fixtures/typescript/services/composer/platformatic.composer.json +1 -1
- package/fixtures/typescript/services/movies/global.d.ts +2 -3
- package/fixtures/typescript/services/movies/platformatic.db.json +1 -1
- package/fixtures/typescript/services/movies/types/Movie.d.ts +3 -3
- package/fixtures/typescript/services/movies/types/index.d.ts +6 -6
- package/fixtures/typescript/services/titles/client/client.d.ts +35 -35
- package/fixtures/typescript/services/titles/platformatic.service.json +1 -1
- package/fixtures/typescript-custom-flags/platformatic.runtime.json +2 -2
- package/fixtures/typescript-custom-flags/services/composer/platformatic.composer.json +1 -1
- package/fixtures/typescript-custom-flags/services/movies/global.d.ts +2 -3
- package/fixtures/typescript-custom-flags/services/movies/platformatic.db.json +1 -1
- package/fixtures/typescript-custom-flags/services/movies/types/Movie.d.ts +3 -3
- package/fixtures/typescript-custom-flags/services/movies/types/index.d.ts +6 -6
- package/fixtures/typescript-custom-flags/services/titles/client/client.d.ts +35 -35
- package/fixtures/typescript-custom-flags/services/titles/platformatic.service.json +1 -1
- package/fixtures/typescript-no-env/platformatic.runtime.json +2 -2
- package/fixtures/typescript-no-env/services/composer/platformatic.composer.json +1 -1
- package/fixtures/typescript-no-env/services/movies/global.d.ts +2 -3
- package/fixtures/typescript-no-env/services/movies/platformatic.db.json +1 -1
- package/fixtures/typescript-no-env/services/movies/types/Movie.d.ts +3 -3
- package/fixtures/typescript-no-env/services/movies/types/index.d.ts +6 -6
- package/fixtures/typescript-no-env/services/titles/client/client.d.ts +35 -35
- package/fixtures/typescript-no-env/services/titles/platformatic.service.json +1 -1
- package/index.d.ts +7 -8
- package/index.js +14 -10
- package/index.test-d.ts +10 -12
- package/lib/build-server.js +5 -11
- package/lib/compile.js +11 -10
- package/lib/config.js +21 -14
- package/lib/dependencies.js +2 -1
- package/lib/errors.js +3 -2
- package/lib/generator/errors.js +1 -1
- package/lib/generator/runtime-generator.d.ts +15 -15
- package/lib/generator/runtime-generator.js +92 -63
- package/lib/logger.js +55 -0
- package/lib/management-api.js +29 -44
- package/lib/prom-server.js +5 -9
- package/lib/runtime.js +955 -0
- package/lib/schema.js +79 -76
- package/lib/start.js +35 -113
- package/lib/upgrade.js +4 -3
- package/lib/utils.js +49 -1
- package/lib/versions/v1.36.0.js +1 -1
- package/lib/versions/v1.5.0.js +1 -1
- package/lib/versions/v2.0.0.js +17 -0
- package/lib/worker/app.js +250 -0
- package/lib/worker/default-stackable.js +27 -0
- package/lib/worker/itc.js +128 -0
- package/lib/worker/main.js +127 -0
- package/lib/worker/symbols.js +7 -0
- package/package.json +25 -25
- package/runtime.mjs +4 -4
- package/schema.json +824 -0
- package/lib/api-client.js +0 -500
- package/lib/api.js +0 -420
- package/lib/app.js +0 -397
- package/lib/load-config.js +0 -12
- package/lib/loader.mjs +0 -103
- package/lib/message-port-writable.js +0 -50
- package/lib/worker.js +0 -182
- /package/lib/{interceptors.js → worker/interceptors.js} +0 -0
package/lib/api-client.js
DELETED
|
@@ -1,500 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const { tmpdir } = require('node:os')
|
|
4
|
-
const { join } = require('node:path')
|
|
5
|
-
const { once, EventEmitter } = require('node:events')
|
|
6
|
-
const { randomUUID, createHash } = require('node:crypto')
|
|
7
|
-
const { createReadStream, watch } = require('node:fs')
|
|
8
|
-
const { readdir, readFile, stat, access } = require('node:fs/promises')
|
|
9
|
-
const { setTimeout: sleep } = require('node:timers/promises')
|
|
10
|
-
const errors = require('./errors')
|
|
11
|
-
const ts = require('tail-file-stream')
|
|
12
|
-
|
|
13
|
-
const platformaticVersion = require('../package.json').version
|
|
14
|
-
|
|
15
|
-
const MAX_LISTENERS_COUNT = 100
|
|
16
|
-
const MAX_METRICS_QUEUE_LENGTH = 5 * 60 // 5 minutes in seconds
|
|
17
|
-
const COLLECT_METRICS_TIMEOUT = 1000
|
|
18
|
-
|
|
19
|
-
class RuntimeApiClient extends EventEmitter {
|
|
20
|
-
#exitCode
|
|
21
|
-
#exitPromise
|
|
22
|
-
#configManager
|
|
23
|
-
#runtimeTmpDir
|
|
24
|
-
#metrics
|
|
25
|
-
#metricsTimeout
|
|
26
|
-
|
|
27
|
-
constructor (worker, configManager) {
|
|
28
|
-
super()
|
|
29
|
-
this.setMaxListeners(MAX_LISTENERS_COUNT)
|
|
30
|
-
|
|
31
|
-
this.#configManager = configManager
|
|
32
|
-
this.#runtimeTmpDir = getRuntimeTmpDir(configManager.dirname)
|
|
33
|
-
|
|
34
|
-
this.setWorker(worker)
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
async setWorker (worker) {
|
|
38
|
-
if (!worker) {
|
|
39
|
-
throw new errors.WorkerIsRequired()
|
|
40
|
-
}
|
|
41
|
-
if (this.worker) {
|
|
42
|
-
this.worker.removeAllListeners('message')
|
|
43
|
-
// Ignore all things that happen after the worker has been replaced
|
|
44
|
-
this.#exitPromise.catch(() => {})
|
|
45
|
-
}
|
|
46
|
-
this.worker = worker
|
|
47
|
-
this.#exitPromise = this.#exitHandler()
|
|
48
|
-
this.worker.on('message', (message) => {
|
|
49
|
-
if (message.operationId) {
|
|
50
|
-
this.emit(message.operationId, message)
|
|
51
|
-
}
|
|
52
|
-
})
|
|
53
|
-
|
|
54
|
-
if (this.started) {
|
|
55
|
-
await this.start()
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
async #getRuntimePackageJson () {
|
|
60
|
-
const runtimeDir = this.#configManager.dirname
|
|
61
|
-
const packageJsonPath = join(runtimeDir, 'package.json')
|
|
62
|
-
const packageJsonFile = await readFile(packageJsonPath, 'utf8')
|
|
63
|
-
const packageJson = JSON.parse(packageJsonFile)
|
|
64
|
-
return packageJson
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
async getRuntimeMetadata () {
|
|
68
|
-
const packageJson = await this.#getRuntimePackageJson()
|
|
69
|
-
const entrypointDetails = await this.getEntrypointDetails()
|
|
70
|
-
|
|
71
|
-
return {
|
|
72
|
-
pid: process.pid,
|
|
73
|
-
cwd: process.cwd(),
|
|
74
|
-
argv: process.argv,
|
|
75
|
-
uptimeSeconds: Math.floor(process.uptime()),
|
|
76
|
-
execPath: process.execPath,
|
|
77
|
-
nodeVersion: process.version,
|
|
78
|
-
projectDir: this.#configManager.dirname,
|
|
79
|
-
packageName: packageJson.name ?? null,
|
|
80
|
-
packageVersion: packageJson.version ?? null,
|
|
81
|
-
url: entrypointDetails?.url ?? null,
|
|
82
|
-
platformaticVersion
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
getRuntimeConfig () {
|
|
87
|
-
return this.#configManager.current
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
async start () {
|
|
91
|
-
const address = await this.#sendCommand('plt:start-services')
|
|
92
|
-
this.started = true
|
|
93
|
-
this.emit('start', address)
|
|
94
|
-
return address
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
async close () {
|
|
98
|
-
this.started = false
|
|
99
|
-
await this.#sendCommand('plt:stop-services')
|
|
100
|
-
|
|
101
|
-
this.worker.postMessage({ command: 'plt:close' })
|
|
102
|
-
const res = await Promise.race([
|
|
103
|
-
this.#exitPromise,
|
|
104
|
-
// We must kill the worker if it doesn't exit in 10 seconds
|
|
105
|
-
// because it may be stuck in an infinite loop.
|
|
106
|
-
// This is a workaround for
|
|
107
|
-
// https://github.com/nodejs/node/issues/47748
|
|
108
|
-
// https://github.com/nodejs/node/issues/49344
|
|
109
|
-
// Remove once https://github.com/nodejs/node/pull/51290 is released
|
|
110
|
-
// on all lines.
|
|
111
|
-
// Likely to be removed when we drop support for Node.js 18.
|
|
112
|
-
sleep(10000, 'timeout', { ref: false })
|
|
113
|
-
])
|
|
114
|
-
|
|
115
|
-
if (res === 'timeout') {
|
|
116
|
-
this.worker.unref()
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
async restart () {
|
|
121
|
-
return this.#sendCommand('plt:restart-services')
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
async getEntrypointDetails () {
|
|
125
|
-
return this.#sendCommand('plt:get-entrypoint-details')
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
async getServices () {
|
|
129
|
-
return this.#sendCommand('plt:get-services')
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
async getServiceDetails (id) {
|
|
133
|
-
return this.#sendCommand('plt:get-service-details', { id })
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
async getServiceConfig (id) {
|
|
137
|
-
return this.#sendCommand('plt:get-service-config', { id })
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
async getServiceOpenapiSchema (id) {
|
|
141
|
-
return this.#sendCommand('plt:get-service-openapi-schema', { id })
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
async getServiceGraphqlSchema (id) {
|
|
145
|
-
return this.#sendCommand('plt:get-service-graphql-schema', { id })
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
async getMetrics (format = 'json') {
|
|
149
|
-
return this.#sendCommand('plt:get-metrics', { format })
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
async startService (id) {
|
|
153
|
-
return this.#sendCommand('plt:start-service', { id })
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
async stopService (id) {
|
|
157
|
-
return this.#sendCommand('plt:stop-service', { id })
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
async inject (id, injectParams) {
|
|
161
|
-
return this.#sendCommand('plt:inject', { id, injectParams })
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
getCachedMetrics () {
|
|
165
|
-
return this.#metrics
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
async getFormattedMetrics () {
|
|
169
|
-
const { metrics } = await this.getMetrics()
|
|
170
|
-
|
|
171
|
-
if (metrics === null) return null
|
|
172
|
-
|
|
173
|
-
const entrypointDetails = await this.getEntrypointDetails()
|
|
174
|
-
const entrypointConfig = await this.getServiceConfig(entrypointDetails.id)
|
|
175
|
-
const entrypointMetricsPrefix = entrypointConfig.metrics?.prefix
|
|
176
|
-
|
|
177
|
-
const cpuMetric = metrics.find(
|
|
178
|
-
(metric) => metric.name === 'process_cpu_percent_usage'
|
|
179
|
-
)
|
|
180
|
-
const rssMetric = metrics.find(
|
|
181
|
-
(metric) => metric.name === 'process_resident_memory_bytes'
|
|
182
|
-
)
|
|
183
|
-
const totalHeapSizeMetric = metrics.find(
|
|
184
|
-
(metric) => metric.name === 'nodejs_heap_size_total_bytes'
|
|
185
|
-
)
|
|
186
|
-
const usedHeapSizeMetric = metrics.find(
|
|
187
|
-
(metric) => metric.name === 'nodejs_heap_size_used_bytes'
|
|
188
|
-
)
|
|
189
|
-
const heapSpaceSizeTotalMetric = metrics.find(
|
|
190
|
-
(metric) => metric.name === 'nodejs_heap_space_size_total_bytes'
|
|
191
|
-
)
|
|
192
|
-
const newSpaceSizeTotalMetric = heapSpaceSizeTotalMetric.values.find(
|
|
193
|
-
(value) => value.labels.space === 'new'
|
|
194
|
-
)
|
|
195
|
-
const oldSpaceSizeTotalMetric = heapSpaceSizeTotalMetric.values.find(
|
|
196
|
-
(value) => value.labels.space === 'old'
|
|
197
|
-
)
|
|
198
|
-
const eventLoopUtilizationMetric = metrics.find(
|
|
199
|
-
(metric) => metric.name === 'nodejs_eventloop_utilization'
|
|
200
|
-
)
|
|
201
|
-
|
|
202
|
-
let p50Value = 0
|
|
203
|
-
let p90Value = 0
|
|
204
|
-
let p95Value = 0
|
|
205
|
-
let p99Value = 0
|
|
206
|
-
|
|
207
|
-
if (entrypointMetricsPrefix) {
|
|
208
|
-
const metricName = entrypointMetricsPrefix + 'http_request_all_summary_seconds'
|
|
209
|
-
const httpLatencyMetrics = metrics.find((metric) => metric.name === metricName)
|
|
210
|
-
|
|
211
|
-
p50Value = httpLatencyMetrics.values.find(
|
|
212
|
-
(value) => value.labels.quantile === 0.5
|
|
213
|
-
).value || 0
|
|
214
|
-
p90Value = httpLatencyMetrics.values.find(
|
|
215
|
-
(value) => value.labels.quantile === 0.9
|
|
216
|
-
).value || 0
|
|
217
|
-
p95Value = httpLatencyMetrics.values.find(
|
|
218
|
-
(value) => value.labels.quantile === 0.95
|
|
219
|
-
).value || 0
|
|
220
|
-
p99Value = httpLatencyMetrics.values.find(
|
|
221
|
-
(value) => value.labels.quantile === 0.99
|
|
222
|
-
).value || 0
|
|
223
|
-
|
|
224
|
-
p50Value = Math.round(p50Value * 1000)
|
|
225
|
-
p90Value = Math.round(p90Value * 1000)
|
|
226
|
-
p95Value = Math.round(p95Value * 1000)
|
|
227
|
-
p99Value = Math.round(p99Value * 1000)
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
const cpu = cpuMetric.values[0].value
|
|
231
|
-
const rss = rssMetric.values[0].value
|
|
232
|
-
const elu = eventLoopUtilizationMetric.values[0].value
|
|
233
|
-
const totalHeapSize = totalHeapSizeMetric.values[0].value
|
|
234
|
-
const usedHeapSize = usedHeapSizeMetric.values[0].value
|
|
235
|
-
const newSpaceSize = newSpaceSizeTotalMetric.value
|
|
236
|
-
const oldSpaceSize = oldSpaceSizeTotalMetric.value
|
|
237
|
-
|
|
238
|
-
const formattedMetrics = {
|
|
239
|
-
version: 1,
|
|
240
|
-
date: new Date().toISOString(),
|
|
241
|
-
cpu,
|
|
242
|
-
elu,
|
|
243
|
-
rss,
|
|
244
|
-
totalHeapSize,
|
|
245
|
-
usedHeapSize,
|
|
246
|
-
newSpaceSize,
|
|
247
|
-
oldSpaceSize,
|
|
248
|
-
entrypoint: {
|
|
249
|
-
latency: {
|
|
250
|
-
p50: p50Value,
|
|
251
|
-
p90: p90Value,
|
|
252
|
-
p95: p95Value,
|
|
253
|
-
p99: p99Value
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
return formattedMetrics
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
startCollectingMetrics () {
|
|
261
|
-
this.#metrics = []
|
|
262
|
-
this.#metricsTimeout = setInterval(async () => {
|
|
263
|
-
let metrics = null
|
|
264
|
-
try {
|
|
265
|
-
metrics = await this.getFormattedMetrics()
|
|
266
|
-
} catch (error) {
|
|
267
|
-
if (!(error instanceof errors.RuntimeExitedError)) {
|
|
268
|
-
// TODO(mcollina): use the logger
|
|
269
|
-
console.error('Error collecting metrics', error)
|
|
270
|
-
}
|
|
271
|
-
return
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
this.emit('metrics', metrics)
|
|
275
|
-
this.#metrics.push(metrics)
|
|
276
|
-
if (this.#metrics.length > MAX_METRICS_QUEUE_LENGTH) {
|
|
277
|
-
this.#metrics.shift()
|
|
278
|
-
}
|
|
279
|
-
}, COLLECT_METRICS_TIMEOUT).unref()
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
async pipeLogsStream (writableStream, logger, startLogId, endLogId, runtimePID) {
|
|
283
|
-
endLogId = endLogId || Infinity
|
|
284
|
-
runtimePID = runtimePID ?? process.pid
|
|
285
|
-
|
|
286
|
-
const runtimeLogFiles = await this.#getRuntimeLogFiles(runtimePID)
|
|
287
|
-
if (runtimeLogFiles.length === 0) {
|
|
288
|
-
writableStream.end()
|
|
289
|
-
return
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
let latestFileId = parseInt(runtimeLogFiles.at(-1).slice('logs.'.length))
|
|
293
|
-
|
|
294
|
-
let waiting = false
|
|
295
|
-
let fileStream = null
|
|
296
|
-
let fileId = startLogId ?? latestFileId
|
|
297
|
-
|
|
298
|
-
const runtimeLogsDir = this.#getRuntimeLogsDir(runtimePID)
|
|
299
|
-
|
|
300
|
-
const watcher = watch(runtimeLogsDir, async (event, filename) => {
|
|
301
|
-
if (event === 'rename' && filename.startsWith('logs')) {
|
|
302
|
-
const logFileId = parseInt(filename.slice('logs.'.length))
|
|
303
|
-
if (logFileId > latestFileId) {
|
|
304
|
-
latestFileId = logFileId
|
|
305
|
-
if (waiting) {
|
|
306
|
-
streamLogFile(++fileId)
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
}).unref()
|
|
311
|
-
|
|
312
|
-
const streamLogFile = () => {
|
|
313
|
-
if (fileId > endLogId) {
|
|
314
|
-
writableStream.end()
|
|
315
|
-
return
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
const fileName = 'logs.' + fileId
|
|
319
|
-
const filePath = join(runtimeLogsDir, fileName)
|
|
320
|
-
|
|
321
|
-
const prevFileStream = fileStream
|
|
322
|
-
|
|
323
|
-
fileStream = ts.createReadStream(filePath)
|
|
324
|
-
fileStream.pipe(writableStream, { end: false })
|
|
325
|
-
|
|
326
|
-
if (prevFileStream) {
|
|
327
|
-
prevFileStream.unpipe(writableStream)
|
|
328
|
-
prevFileStream.destroy()
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
fileStream.on('error', (err) => {
|
|
332
|
-
logger.error(err, 'Error streaming log file')
|
|
333
|
-
fileStream.destroy()
|
|
334
|
-
watcher.close()
|
|
335
|
-
writableStream.end()
|
|
336
|
-
})
|
|
337
|
-
|
|
338
|
-
fileStream.on('data', () => {
|
|
339
|
-
waiting = false
|
|
340
|
-
})
|
|
341
|
-
|
|
342
|
-
fileStream.on('eof', () => {
|
|
343
|
-
if (fileId >= endLogId) {
|
|
344
|
-
writableStream.end()
|
|
345
|
-
return
|
|
346
|
-
}
|
|
347
|
-
if (latestFileId > fileId) {
|
|
348
|
-
streamLogFile(++fileId)
|
|
349
|
-
} else {
|
|
350
|
-
waiting = true
|
|
351
|
-
}
|
|
352
|
-
})
|
|
353
|
-
|
|
354
|
-
return fileStream
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
streamLogFile(fileId)
|
|
358
|
-
|
|
359
|
-
writableStream.on('close', () => {
|
|
360
|
-
watcher.close()
|
|
361
|
-
fileStream.destroy()
|
|
362
|
-
})
|
|
363
|
-
writableStream.on('error', () => {
|
|
364
|
-
watcher.close()
|
|
365
|
-
fileStream.destroy()
|
|
366
|
-
})
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
async getLogIds (runtimePID) {
|
|
370
|
-
runtimePID = runtimePID ?? process.pid
|
|
371
|
-
|
|
372
|
-
const runtimeLogFiles = await this.#getRuntimeLogFiles(runtimePID)
|
|
373
|
-
const runtimeLogIds = []
|
|
374
|
-
|
|
375
|
-
for (const logFile of runtimeLogFiles) {
|
|
376
|
-
const logId = parseInt(logFile.slice('logs.'.length))
|
|
377
|
-
runtimeLogIds.push(logId)
|
|
378
|
-
}
|
|
379
|
-
return runtimeLogIds
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
async getAllLogIds () {
|
|
383
|
-
const runtimesLogFiles = await this.#getAllLogsFiles()
|
|
384
|
-
const runtimesLogsIds = []
|
|
385
|
-
|
|
386
|
-
for (const runtime of runtimesLogFiles) {
|
|
387
|
-
const runtimeLogIds = []
|
|
388
|
-
for (const logFile of runtime.runtimeLogFiles) {
|
|
389
|
-
const logId = parseInt(logFile.slice('logs.'.length))
|
|
390
|
-
runtimeLogIds.push(logId)
|
|
391
|
-
}
|
|
392
|
-
runtimesLogsIds.push({
|
|
393
|
-
pid: runtime.runtimePID,
|
|
394
|
-
indexes: runtimeLogIds
|
|
395
|
-
})
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
return runtimesLogsIds
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
async getLogFileStream (logFileId, runtimePID) {
|
|
402
|
-
const runtimeLogsDir = this.#getRuntimeLogsDir(runtimePID)
|
|
403
|
-
const filePath = join(runtimeLogsDir, `logs.${logFileId}`)
|
|
404
|
-
return createReadStream(filePath)
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
#getRuntimeLogsDir (runtimePID) {
|
|
408
|
-
return join(this.#runtimeTmpDir, runtimePID.toString(), 'logs')
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
async #getRuntimeLogFiles (runtimePID) {
|
|
412
|
-
const runtimeLogsDir = this.#getRuntimeLogsDir(runtimePID)
|
|
413
|
-
const runtimeLogsFiles = await readdir(runtimeLogsDir)
|
|
414
|
-
return runtimeLogsFiles
|
|
415
|
-
.filter((file) => file.startsWith('logs'))
|
|
416
|
-
.sort((log1, log2) => {
|
|
417
|
-
const index1 = parseInt(log1.slice('logs.'.length))
|
|
418
|
-
const index2 = parseInt(log2.slice('logs.'.length))
|
|
419
|
-
return index1 - index2
|
|
420
|
-
})
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
async #getAllLogsFiles () {
|
|
424
|
-
try {
|
|
425
|
-
await access(this.#runtimeTmpDir)
|
|
426
|
-
} catch (error) {
|
|
427
|
-
return []
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
const runtimePIDs = await readdir(this.#runtimeTmpDir)
|
|
431
|
-
const runtimesLogFiles = []
|
|
432
|
-
|
|
433
|
-
for (const runtimePID of runtimePIDs) {
|
|
434
|
-
const runtimeLogsDir = this.#getRuntimeLogsDir(runtimePID)
|
|
435
|
-
const runtimeLogsDirStat = await stat(runtimeLogsDir)
|
|
436
|
-
const runtimeLogFiles = await this.#getRuntimeLogFiles(runtimePID)
|
|
437
|
-
const lastModified = runtimeLogsDirStat.mtime
|
|
438
|
-
|
|
439
|
-
runtimesLogFiles.push({
|
|
440
|
-
runtimePID: parseInt(runtimePID),
|
|
441
|
-
runtimeLogFiles,
|
|
442
|
-
lastModified
|
|
443
|
-
})
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
return runtimesLogFiles.sort(
|
|
447
|
-
(runtime1, runtime2) => runtime1.lastModified - runtime2.lastModified
|
|
448
|
-
)
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
async #sendCommand (command, params = {}) {
|
|
452
|
-
const operationId = randomUUID()
|
|
453
|
-
this.worker.postMessage({ operationId, command, params })
|
|
454
|
-
const [message] = await Promise.race(
|
|
455
|
-
[once(this, operationId), this.#exitPromise]
|
|
456
|
-
)
|
|
457
|
-
|
|
458
|
-
if (this.#exitCode !== undefined) {
|
|
459
|
-
if (this.exitCode === 1) {
|
|
460
|
-
throw new errors.AddressInUseError()
|
|
461
|
-
}
|
|
462
|
-
throw new errors.RuntimeExitedError()
|
|
463
|
-
}
|
|
464
|
-
const { error, data, code } = message
|
|
465
|
-
if (error !== null) {
|
|
466
|
-
const err = new Error(error)
|
|
467
|
-
err.code = code
|
|
468
|
-
throw err
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
return JSON.parse(data)
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
async #exitHandler () {
|
|
475
|
-
this.#exitCode = undefined
|
|
476
|
-
return once(this.worker, 'exit').then((msg) => {
|
|
477
|
-
clearInterval(this.#metricsTimeout)
|
|
478
|
-
this.#exitCode = msg[0]
|
|
479
|
-
this.emit('close')
|
|
480
|
-
return msg
|
|
481
|
-
})
|
|
482
|
-
}
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
function getRuntimeTmpDir (runtimeDir) {
|
|
486
|
-
const platformaticTmpDir = join(tmpdir(), 'platformatic', 'applications')
|
|
487
|
-
const runtimeDirHash = createHash('md5').update(runtimeDir).digest('hex')
|
|
488
|
-
return join(platformaticTmpDir, runtimeDirHash)
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
function getRuntimeLogsDir (runtimeDir, runtimePID) {
|
|
492
|
-
const runtimeTmpDir = getRuntimeTmpDir(runtimeDir)
|
|
493
|
-
return join(runtimeTmpDir, runtimePID.toString(), 'logs')
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
module.exports = {
|
|
497
|
-
RuntimeApiClient,
|
|
498
|
-
getRuntimeTmpDir,
|
|
499
|
-
getRuntimeLogsDir
|
|
500
|
-
}
|