@platformatic/runtime 3.45.0 → 3.46.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/lib/runtime.js +44 -3
- package/package.json +15 -15
- package/schema.json +1 -1
package/lib/runtime.js
CHANGED
|
@@ -117,6 +117,7 @@ export class Runtime extends EventEmitter {
|
|
|
117
117
|
#concurrency
|
|
118
118
|
#entrypointId
|
|
119
119
|
#url
|
|
120
|
+
#entrypointPort
|
|
120
121
|
|
|
121
122
|
#healthMetricsTimer
|
|
122
123
|
|
|
@@ -157,6 +158,7 @@ export class Runtime extends EventEmitter {
|
|
|
157
158
|
this.#applications = new Map()
|
|
158
159
|
this.#workers = new RoundRobinMap()
|
|
159
160
|
this.#url = undefined
|
|
161
|
+
this.#entrypointPort = undefined
|
|
160
162
|
this.#channelCreationHook = createChannelCreationHook(this.#config)
|
|
161
163
|
this.#meshInterceptor = createThreadInterceptor({
|
|
162
164
|
domain: '.plt.local',
|
|
@@ -680,6 +682,14 @@ export class Runtime extends EventEmitter {
|
|
|
680
682
|
if (this.#restartingApplications.has(id)) {
|
|
681
683
|
return
|
|
682
684
|
}
|
|
685
|
+
|
|
686
|
+
// Wait for the runtime to be fully started before attempting a restart.
|
|
687
|
+
// Restarting an application while the runtime is still starting causes
|
|
688
|
+
// races between the start and stop ITC commands in the worker thread.
|
|
689
|
+
if (this.#status === 'starting') {
|
|
690
|
+
await once(this, 'started')
|
|
691
|
+
}
|
|
692
|
+
|
|
683
693
|
this.#restartingApplications.add(id)
|
|
684
694
|
|
|
685
695
|
try {
|
|
@@ -1852,6 +1862,13 @@ export class Runtime extends EventEmitter {
|
|
|
1852
1862
|
})
|
|
1853
1863
|
|
|
1854
1864
|
worker[kITC].on('request:restart', async () => {
|
|
1865
|
+
// Do not restart applications that are not fully started yet or when the runtime is still starting.
|
|
1866
|
+
// The gateway sends request:restart when it receives application:added events,
|
|
1867
|
+
// which can arrive while the worker is still in the starting phase.
|
|
1868
|
+
if (this.#status !== 'started' || worker[kWorkerStatus] !== 'started') {
|
|
1869
|
+
return
|
|
1870
|
+
}
|
|
1871
|
+
|
|
1855
1872
|
try {
|
|
1856
1873
|
await this.restartApplication(applicationId)
|
|
1857
1874
|
} catch (e) {
|
|
@@ -2153,6 +2170,20 @@ export class Runtime extends EventEmitter {
|
|
|
2153
2170
|
|
|
2154
2171
|
if (workerUrl) {
|
|
2155
2172
|
this.#url = workerUrl
|
|
2173
|
+
|
|
2174
|
+
// Pin the entrypoint port so that subsequent restarts (especially with
|
|
2175
|
+
// stopBeforeStart when reuseTcpPorts is false) bind to the same port
|
|
2176
|
+
// instead of getting a new random one.
|
|
2177
|
+
if (applicationConfig.entrypoint) {
|
|
2178
|
+
try {
|
|
2179
|
+
const boundPort = Number(new URL(workerUrl).port)
|
|
2180
|
+
if (boundPort) {
|
|
2181
|
+
this.#entrypointPort = boundPort
|
|
2182
|
+
}
|
|
2183
|
+
} catch {
|
|
2184
|
+
// URL parsing failed, leave unchanged
|
|
2185
|
+
}
|
|
2186
|
+
}
|
|
2156
2187
|
}
|
|
2157
2188
|
|
|
2158
2189
|
// Wait for the interceptor to be ready
|
|
@@ -2379,6 +2410,16 @@ export class Runtime extends EventEmitter {
|
|
|
2379
2410
|
applicationConfig.entrypoint &&
|
|
2380
2411
|
(config.reuseTcpPorts === false || applicationConfig.reuseTcpPorts === false || !features.node.reusePort)
|
|
2381
2412
|
|
|
2413
|
+
// When we must stop before start (no reusePort available), pin the entrypoint
|
|
2414
|
+
// port in the config so the replacement worker binds to the same port.
|
|
2415
|
+
// We only do this for stopBeforeStart because when reusePort is available
|
|
2416
|
+
// the new worker starts alongside the old one and must use port 0 to avoid
|
|
2417
|
+
// SO_REUSEPORT routing requests to the stale old worker.
|
|
2418
|
+
let configForNewWorker = config
|
|
2419
|
+
if (stopBeforeStart && this.#entrypointPort && config.server) {
|
|
2420
|
+
configForNewWorker = { ...config, server: { ...config.server, port: this.#entrypointPort } }
|
|
2421
|
+
}
|
|
2422
|
+
|
|
2382
2423
|
if (stopBeforeStart) {
|
|
2383
2424
|
await this.#removeWorker(workersCount, applicationId, index, worker, silent, label)
|
|
2384
2425
|
}
|
|
@@ -2388,8 +2429,8 @@ export class Runtime extends EventEmitter {
|
|
|
2388
2429
|
this.logger.debug(`Preparing to start a replacement for ${label} ...`)
|
|
2389
2430
|
}
|
|
2390
2431
|
|
|
2391
|
-
// Create a new worker
|
|
2392
|
-
newWorker = await this.#setupWorker(
|
|
2432
|
+
// Create a new worker (use configForNewWorker which may have a pinned port for stopBeforeStart)
|
|
2433
|
+
newWorker = await this.#setupWorker(configForNewWorker, applicationConfig, workersCount, applicationId, index, false)
|
|
2393
2434
|
|
|
2394
2435
|
// Make sure the runtime hasn't been stopped in the meanwhile
|
|
2395
2436
|
if (this.#status !== 'started') {
|
|
@@ -2397,7 +2438,7 @@ export class Runtime extends EventEmitter {
|
|
|
2397
2438
|
}
|
|
2398
2439
|
|
|
2399
2440
|
// Add the worker to the mesh
|
|
2400
|
-
await this.#startWorker(
|
|
2441
|
+
await this.#startWorker(configForNewWorker, applicationConfig, workersCount, applicationId, index, false, 0, newWorker, true)
|
|
2401
2442
|
|
|
2402
2443
|
// Make sure the runtime hasn't been stopped in the meanwhile
|
|
2403
2444
|
if (this.#status !== 'started') {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@platformatic/runtime",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.46.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -35,14 +35,14 @@
|
|
|
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": "3.
|
|
39
|
-
"@platformatic/db": "3.
|
|
40
|
-
"@platformatic/gateway": "3.
|
|
41
|
-
"@platformatic/
|
|
42
|
-
"@platformatic/
|
|
43
|
-
"@platformatic/
|
|
44
|
-
"@platformatic/
|
|
45
|
-
"@platformatic/wattpm-pprof-capture": "3.
|
|
38
|
+
"@platformatic/composer": "3.46.0",
|
|
39
|
+
"@platformatic/db": "3.46.0",
|
|
40
|
+
"@platformatic/gateway": "3.46.0",
|
|
41
|
+
"@platformatic/sql-graphql": "3.46.0",
|
|
42
|
+
"@platformatic/sql-mapper": "3.46.0",
|
|
43
|
+
"@platformatic/node": "3.46.0",
|
|
44
|
+
"@platformatic/service": "3.46.0",
|
|
45
|
+
"@platformatic/wattpm-pprof-capture": "3.46.0"
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
48
|
"@fastify/accepts": "^5.0.0",
|
|
@@ -72,12 +72,12 @@
|
|
|
72
72
|
"undici": "^7.0.0",
|
|
73
73
|
"undici-thread-interceptor": "^1.3.1",
|
|
74
74
|
"ws": "^8.16.0",
|
|
75
|
-
"@platformatic/basic": "3.
|
|
76
|
-
"@platformatic/foundation": "3.
|
|
77
|
-
"@platformatic/generators": "3.
|
|
78
|
-
"@platformatic/itc": "3.
|
|
79
|
-
"@platformatic/metrics": "3.
|
|
80
|
-
"@platformatic/telemetry": "3.
|
|
75
|
+
"@platformatic/basic": "3.46.0",
|
|
76
|
+
"@platformatic/foundation": "3.46.0",
|
|
77
|
+
"@platformatic/generators": "3.46.0",
|
|
78
|
+
"@platformatic/itc": "3.46.0",
|
|
79
|
+
"@platformatic/metrics": "3.46.0",
|
|
80
|
+
"@platformatic/telemetry": "3.46.0"
|
|
81
81
|
},
|
|
82
82
|
"engines": {
|
|
83
83
|
"node": ">=22.19.0"
|
package/schema.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"$id": "https://schemas.platformatic.dev/@platformatic/runtime/3.
|
|
2
|
+
"$id": "https://schemas.platformatic.dev/@platformatic/runtime/3.46.0.json",
|
|
3
3
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
4
4
|
"title": "Platformatic Runtime Config",
|
|
5
5
|
"type": "object",
|