@platformatic/runtime 2.74.3 → 2.75.0-alpha.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/README.md +1 -1
- package/config.d.ts +1 -1
- package/lib/config.js +78 -1
- package/lib/generator/README.md +3 -3
- package/lib/generator/runtime-generator.js +1 -1
- package/lib/management-api.js +17 -0
- package/lib/runtime.js +12 -0
- package/lib/worker/app.js +2 -0
- package/package.json +16 -16
- package/schema.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @platformatic/runtime
|
|
2
2
|
|
|
3
|
-
Check out the full documentation for Platformatic Runtime on [our website](https://docs.platformatic.dev/docs/runtime/overview).
|
|
3
|
+
Check out the full documentation for Platformatic Runtime on [our website](https://docs.platformatic.dev/docs/reference/runtime/overview).
|
|
4
4
|
|
|
5
5
|
## Install
|
|
6
6
|
|
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 HttpsSchemasPlatformaticDevPlatformaticRuntime2750Alpha0Json = {
|
|
9
9
|
[k: string]: unknown;
|
|
10
10
|
} & {
|
|
11
11
|
$schema?: string;
|
package/lib/config.js
CHANGED
|
@@ -16,6 +16,33 @@ const { schema } = require('./schema')
|
|
|
16
16
|
const upgrade = require('./upgrade')
|
|
17
17
|
const { parseArgs } = require('node:util')
|
|
18
18
|
|
|
19
|
+
function autoDetectPprofCapture (config) {
|
|
20
|
+
// Check if package is installed
|
|
21
|
+
try {
|
|
22
|
+
let pprofCapturePath
|
|
23
|
+
try {
|
|
24
|
+
pprofCapturePath = require.resolve('@platformatic/watt-pprof-capture')
|
|
25
|
+
} catch (err) {
|
|
26
|
+
pprofCapturePath = require.resolve('../../watt-pprof-capture/index.js')
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Add to preload if not already present
|
|
30
|
+
if (!config.preload) {
|
|
31
|
+
config.preload = []
|
|
32
|
+
} else if (typeof config.preload === 'string') {
|
|
33
|
+
config.preload = [config.preload]
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (!config.preload.includes(pprofCapturePath)) {
|
|
37
|
+
config.preload.push(pprofCapturePath)
|
|
38
|
+
}
|
|
39
|
+
} catch (err) {
|
|
40
|
+
// Package not installed, skip silently
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return config
|
|
44
|
+
}
|
|
45
|
+
|
|
19
46
|
async function _transformConfig (configManager, args) {
|
|
20
47
|
const config = configManager.current
|
|
21
48
|
|
|
@@ -90,6 +117,41 @@ async function _transformConfig (configManager, args) {
|
|
|
90
117
|
|
|
91
118
|
let hasValidEntrypoint = false
|
|
92
119
|
|
|
120
|
+
// Validate and coerce workers values early to avoid runtime hangs when invalid
|
|
121
|
+
function coercePositiveInteger (value) {
|
|
122
|
+
if (typeof value === 'number') {
|
|
123
|
+
if (!Number.isInteger(value) || value < 1) return null
|
|
124
|
+
return value
|
|
125
|
+
}
|
|
126
|
+
if (typeof value === 'string') {
|
|
127
|
+
// Trim to handle accidental spaces
|
|
128
|
+
const trimmed = value.trim()
|
|
129
|
+
if (trimmed.length === 0) return null
|
|
130
|
+
const num = Number(trimmed)
|
|
131
|
+
if (!Number.isFinite(num) || !Number.isInteger(num) || num < 1) return null
|
|
132
|
+
return num
|
|
133
|
+
}
|
|
134
|
+
return null
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function raiseInvalidWorkersError (location, received, hint) {
|
|
138
|
+
const extra = hint ? ` (${hint})` : ''
|
|
139
|
+
throw new errors.InvalidArgumentError(
|
|
140
|
+
`${location} workers must be a positive integer; received "${received}"${extra}`
|
|
141
|
+
)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Root-level workers
|
|
145
|
+
if (typeof config.workers !== 'undefined') {
|
|
146
|
+
const coerced = coercePositiveInteger(config.workers)
|
|
147
|
+
if (coerced === null) {
|
|
148
|
+
const raw = configManager.currentRaw?.workers
|
|
149
|
+
const hint = typeof raw === 'string' && /\{.*\}/.test(raw) ? 'check your environment variable' : ''
|
|
150
|
+
raiseInvalidWorkersError('Runtime', config.workers, hint)
|
|
151
|
+
}
|
|
152
|
+
config.workers = coerced
|
|
153
|
+
}
|
|
154
|
+
|
|
93
155
|
for (let i = 0; i < services.length; ++i) {
|
|
94
156
|
const service = services[i]
|
|
95
157
|
|
|
@@ -156,6 +218,17 @@ async function _transformConfig (configManager, args) {
|
|
|
156
218
|
}
|
|
157
219
|
}
|
|
158
220
|
|
|
221
|
+
// Validate and coerce per-service workers
|
|
222
|
+
if (typeof service.workers !== 'undefined') {
|
|
223
|
+
const coerced = coercePositiveInteger(service.workers)
|
|
224
|
+
if (coerced === null) {
|
|
225
|
+
const raw = configManager.currentRaw?.services?.[i]?.workers
|
|
226
|
+
const hint = typeof raw === 'string' && /\{.*\}/.test(raw) ? 'check your environment variable' : ''
|
|
227
|
+
raiseInvalidWorkersError(`Service "${service.id}"`, service.workers, hint)
|
|
228
|
+
}
|
|
229
|
+
service.workers = coerced
|
|
230
|
+
}
|
|
231
|
+
|
|
159
232
|
service.entrypoint = service.id === config.entrypoint
|
|
160
233
|
service.dependencies = []
|
|
161
234
|
service.localServiceEnvVars = new Map()
|
|
@@ -226,6 +299,9 @@ async function _transformConfig (configManager, args) {
|
|
|
226
299
|
configManager.current.restartOnError = 0
|
|
227
300
|
}
|
|
228
301
|
}
|
|
302
|
+
|
|
303
|
+
// Auto-detect and add pprof capture if available
|
|
304
|
+
autoDetectPprofCapture(configManager.current)
|
|
229
305
|
}
|
|
230
306
|
|
|
231
307
|
async function platformaticRuntime () {
|
|
@@ -358,5 +434,6 @@ function parseInspectorOptions (configManager) {
|
|
|
358
434
|
module.exports = {
|
|
359
435
|
parseInspectorOptions,
|
|
360
436
|
platformaticRuntime,
|
|
361
|
-
wrapConfigInRuntimeConfig
|
|
437
|
+
wrapConfigInRuntimeConfig,
|
|
438
|
+
autoDetectPprofCapture
|
|
362
439
|
}
|
package/lib/generator/README.md
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
# Platformatic Runtime API
|
|
2
2
|
|
|
3
|
-
This is a generated [Platformatic Runtime](https://docs.platformatic.dev/docs/runtime/overview) application.
|
|
3
|
+
This is a generated [Platformatic Runtime](https://docs.platformatic.dev/docs/reference/runtime/overview) application.
|
|
4
4
|
|
|
5
5
|
## Requirements
|
|
6
6
|
|
|
7
|
-
Platformatic supports macOS, Linux and Windows ([WSL](https://
|
|
8
|
-
You'll need to have [Node.js](https://nodejs.org/)
|
|
7
|
+
Platformatic supports macOS, Linux and Windows ([WSL](https://learn.microsoft.com/en-us/windows/wsl/) recommended).
|
|
8
|
+
You'll need to have [Node.js](https://nodejs.org/) (v20.16.0+ or v22.3.0+)
|
|
9
9
|
|
|
10
10
|
## Setup
|
|
11
11
|
|
package/lib/management-api.js
CHANGED
|
@@ -90,6 +90,23 @@ async function managementApiPlugin (app, opts) {
|
|
|
90
90
|
await runtime.stopService(id)
|
|
91
91
|
})
|
|
92
92
|
|
|
93
|
+
app.post('/services/:id/pprof/start', async (request, reply) => {
|
|
94
|
+
const { id } = request.params
|
|
95
|
+
app.log.debug('start profiling', { id })
|
|
96
|
+
|
|
97
|
+
const options = request.body || {}
|
|
98
|
+
await runtime.startServiceProfiling(id, options)
|
|
99
|
+
reply.code(200).send({})
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
app.post('/services/:id/pprof/stop', async (request, reply) => {
|
|
103
|
+
const { id } = request.params
|
|
104
|
+
app.log.debug('stop profiling', { id })
|
|
105
|
+
|
|
106
|
+
const profileData = await runtime.stopServiceProfiling(id)
|
|
107
|
+
reply.type('application/octet-stream').code(200).send(profileData)
|
|
108
|
+
})
|
|
109
|
+
|
|
93
110
|
app.all('/services/:id/proxy/*', async (request, reply) => {
|
|
94
111
|
const { id, '*': requestUrl } = request.params
|
|
95
112
|
app.log.debug('proxy request', { id, requestUrl })
|
package/lib/runtime.js
CHANGED
|
@@ -795,6 +795,18 @@ class Runtime extends EventEmitter {
|
|
|
795
795
|
return sendViaITC(service, 'getServiceEnv')
|
|
796
796
|
}
|
|
797
797
|
|
|
798
|
+
async startServiceProfiling (id, options = {}, ensureStarted = true) {
|
|
799
|
+
const service = await this.#getServiceById(id, ensureStarted)
|
|
800
|
+
|
|
801
|
+
return sendViaITC(service, 'startProfiling', options)
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
async stopServiceProfiling (id, ensureStarted = true) {
|
|
805
|
+
const service = await this.#getServiceById(id, ensureStarted)
|
|
806
|
+
|
|
807
|
+
return sendViaITC(service, 'stopProfiling')
|
|
808
|
+
}
|
|
809
|
+
|
|
798
810
|
async getServiceOpenapiSchema (id) {
|
|
799
811
|
const service = await this.#getServiceById(id, true)
|
|
800
812
|
|
package/lib/worker/app.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
const { getActiveResourcesInfo } = require('node:process')
|
|
3
4
|
const { existsSync } = require('node:fs')
|
|
4
5
|
const { EventEmitter } = require('node:events')
|
|
5
6
|
const { resolve } = require('node:path')
|
|
@@ -219,6 +220,7 @@ class PlatformaticApp extends EventEmitter {
|
|
|
219
220
|
globalThis.platformatic.onHttpStatsSize(url, size || 0)
|
|
220
221
|
}
|
|
221
222
|
}
|
|
223
|
+
globalThis.platformatic.onActiveResourcesEventLoop(getActiveResourcesInfo().length)
|
|
222
224
|
return this.stackable.getMetrics({ format })
|
|
223
225
|
}
|
|
224
226
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@platformatic/runtime",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.75.0-alpha.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -33,16 +33,16 @@
|
|
|
33
33
|
"neostandard": "^0.12.0",
|
|
34
34
|
"pino-abstract-transport": "^2.0.0",
|
|
35
35
|
"split2": "^4.2.0",
|
|
36
|
-
"tsd": "^0.
|
|
36
|
+
"tsd": "^0.33.0",
|
|
37
37
|
"typescript": "^5.5.4",
|
|
38
38
|
"undici-oidc-interceptor": "^0.5.0",
|
|
39
39
|
"why-is-node-running": "^2.2.2",
|
|
40
|
-
"@platformatic/composer": "2.
|
|
41
|
-
"@platformatic/db": "2.
|
|
42
|
-
"@platformatic/node": "2.
|
|
43
|
-
"@platformatic/service": "2.
|
|
44
|
-
"@platformatic/sql-graphql": "2.
|
|
45
|
-
"@platformatic/sql-mapper": "2.
|
|
40
|
+
"@platformatic/composer": "2.75.0-alpha.0",
|
|
41
|
+
"@platformatic/db": "2.75.0-alpha.0",
|
|
42
|
+
"@platformatic/node": "2.75.0-alpha.0",
|
|
43
|
+
"@platformatic/service": "2.75.0-alpha.0",
|
|
44
|
+
"@platformatic/sql-graphql": "2.75.0-alpha.0",
|
|
45
|
+
"@platformatic/sql-mapper": "2.75.0-alpha.0"
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
48
|
"@fastify/accepts": "^5.0.0",
|
|
@@ -76,14 +76,14 @@
|
|
|
76
76
|
"undici": "^7.0.0",
|
|
77
77
|
"undici-thread-interceptor": "^0.14.0",
|
|
78
78
|
"ws": "^8.16.0",
|
|
79
|
-
"@platformatic/basic": "2.
|
|
80
|
-
"@platformatic/config": "2.
|
|
81
|
-
"@platformatic/generators": "2.
|
|
82
|
-
"@platformatic/metrics": "2.
|
|
83
|
-
"@platformatic/itc": "2.
|
|
84
|
-
"@platformatic/telemetry": "2.
|
|
85
|
-
"@platformatic/ts-compiler": "2.
|
|
86
|
-
"@platformatic/utils": "2.
|
|
79
|
+
"@platformatic/basic": "2.75.0-alpha.0",
|
|
80
|
+
"@platformatic/config": "2.75.0-alpha.0",
|
|
81
|
+
"@platformatic/generators": "2.75.0-alpha.0",
|
|
82
|
+
"@platformatic/metrics": "2.75.0-alpha.0",
|
|
83
|
+
"@platformatic/itc": "2.75.0-alpha.0",
|
|
84
|
+
"@platformatic/telemetry": "2.75.0-alpha.0",
|
|
85
|
+
"@platformatic/ts-compiler": "2.75.0-alpha.0",
|
|
86
|
+
"@platformatic/utils": "2.75.0-alpha.0"
|
|
87
87
|
},
|
|
88
88
|
"scripts": {
|
|
89
89
|
"test": "pnpm run lint && borp --concurrency=1 --timeout=1200000 && tsd",
|
package/schema.json
CHANGED