@platformatic/runtime 0.32.0 → 0.33.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/fixtures/configs/hotreload.json +20 -0
- package/fixtures/monorepo/serviceAppWithLogger/platformatic.service.json +2 -1
- package/fixtures/start-command-in-runtime.js +2 -2
- package/fixtures/telemetry/platformatic.runtime.json +19 -0
- package/fixtures/telemetry/services/echo/platformatic.service.json +19 -0
- package/fixtures/telemetry/services/echo/routes/span.js +8 -0
- package/lib/api.js +5 -3
- package/lib/app.js +50 -38
- package/lib/schema.js +2 -0
- package/lib/start.js +6 -1
- package/lib/unified-api.js +0 -9
- package/package.json +10 -8
- package/runtime.mjs +2 -2
- package/test/app.test.js +21 -5
- package/test/cli/helper.mjs +7 -5
- package/test/cli/start.test.mjs +1 -1
- package/test/cli/watch.test.mjs +82 -9
- package/test/telemetry.test.js +37 -0
- package/test/unified-api.test.js +0 -5
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://platformatic.dev/schemas/v0.32.0/runtime",
|
|
3
|
+
"entrypoint": "serviceApp",
|
|
4
|
+
"allowCycles": true,
|
|
5
|
+
"hotReload": true,
|
|
6
|
+
"autoload": {
|
|
7
|
+
"path": "../monorepo",
|
|
8
|
+
"exclude": ["docs", "composerApp"],
|
|
9
|
+
"mappings": {
|
|
10
|
+
"serviceAppWithLogger": {
|
|
11
|
+
"id": "with-logger",
|
|
12
|
+
"config": "platformatic.service.json"
|
|
13
|
+
},
|
|
14
|
+
"serviceAppWithMultiplePlugins": {
|
|
15
|
+
"id": "multi-plugin-service",
|
|
16
|
+
"config": "platformatic.service.json"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
const assert = require('node:assert')
|
|
3
3
|
const { request } = require('undici')
|
|
4
|
-
const {
|
|
4
|
+
const { startCommand } = require('../lib/unified-api')
|
|
5
5
|
|
|
6
6
|
async function main () {
|
|
7
|
-
const entrypoint = await
|
|
7
|
+
const entrypoint = await startCommand(['-c', process.argv[2]])
|
|
8
8
|
const endpoint = process.argv[3] ?? '/'
|
|
9
9
|
const res = await request(entrypoint + endpoint)
|
|
10
10
|
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://platformatic.dev/schemas/v0.31.0/runtime",
|
|
3
|
+
"entrypoint": "echo",
|
|
4
|
+
"allowCycles": false,
|
|
5
|
+
"hotReload": true,
|
|
6
|
+
"autoload": {
|
|
7
|
+
"path": "services",
|
|
8
|
+
"exclude": [
|
|
9
|
+
"docs"
|
|
10
|
+
]
|
|
11
|
+
},
|
|
12
|
+
"telemetry": {
|
|
13
|
+
"serviceName": "test-runtime",
|
|
14
|
+
"version": "1.0.0",
|
|
15
|
+
"exporter": {
|
|
16
|
+
"type": "memory"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://platformatic.dev/schemas/v0.28.1/service",
|
|
3
|
+
"server": {
|
|
4
|
+
"hostname": "127.0.0.1",
|
|
5
|
+
"port": "0",
|
|
6
|
+
"logger": {
|
|
7
|
+
"level": "info"
|
|
8
|
+
}
|
|
9
|
+
},
|
|
10
|
+
"service": {
|
|
11
|
+
"openapi": true
|
|
12
|
+
},
|
|
13
|
+
"plugins": {
|
|
14
|
+
"paths": [
|
|
15
|
+
"./routes"
|
|
16
|
+
],
|
|
17
|
+
"typescript": false
|
|
18
|
+
}
|
|
19
|
+
}
|
package/lib/api.js
CHANGED
|
@@ -11,10 +11,12 @@ class RuntimeApi {
|
|
|
11
11
|
|
|
12
12
|
constructor (config, logger, loaderPort) {
|
|
13
13
|
this.#services = new Map()
|
|
14
|
+
const telemetryConfig = config.telemetry
|
|
14
15
|
|
|
15
16
|
for (let i = 0; i < config.services.length; ++i) {
|
|
16
17
|
const service = config.services[i]
|
|
17
|
-
const
|
|
18
|
+
const serviceTelemetryConfig = telemetryConfig ? { ...telemetryConfig, serviceName: `${telemetryConfig.serviceName}-${service.id}` } : null
|
|
19
|
+
const app = new PlatformaticApp(service, loaderPort, logger, serviceTelemetryConfig)
|
|
18
20
|
|
|
19
21
|
this.#services.set(service.id, app)
|
|
20
22
|
}
|
|
@@ -47,9 +49,9 @@ class RuntimeApi {
|
|
|
47
49
|
}
|
|
48
50
|
|
|
49
51
|
async #handleProcessLevelEvent (message) {
|
|
50
|
-
|
|
52
|
+
await Promise.allSettled(this.#services.values().map(async (service) => {
|
|
51
53
|
await service.handleProcessLevelEvent(message)
|
|
52
|
-
}
|
|
54
|
+
}))
|
|
53
55
|
}
|
|
54
56
|
|
|
55
57
|
async #executeCommand (message) {
|
package/lib/app.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
'use strict'
|
|
2
|
+
|
|
2
3
|
const { once } = require('node:events')
|
|
3
4
|
const { dirname, basename } = require('node:path')
|
|
4
5
|
const { FileWatcher } = require('@platformatic/utils')
|
|
6
|
+
const debounce = require('debounce')
|
|
5
7
|
const {
|
|
6
8
|
buildServer,
|
|
7
9
|
loadConfig
|
|
@@ -13,9 +15,11 @@ class PlatformaticApp {
|
|
|
13
15
|
#restarting
|
|
14
16
|
#started
|
|
15
17
|
#originalWatch
|
|
18
|
+
#fileWatcher
|
|
16
19
|
#logger
|
|
20
|
+
#telemetryConfig
|
|
17
21
|
|
|
18
|
-
constructor (appConfig, loaderPort, logger) {
|
|
22
|
+
constructor (appConfig, loaderPort, logger, telemetryConfig) {
|
|
19
23
|
this.appConfig = appConfig
|
|
20
24
|
this.config = null
|
|
21
25
|
this.#hotReload = false
|
|
@@ -24,9 +28,11 @@ class PlatformaticApp {
|
|
|
24
28
|
this.server = null
|
|
25
29
|
this.#started = false
|
|
26
30
|
this.#originalWatch = null
|
|
31
|
+
this.#fileWatcher = null
|
|
27
32
|
this.#logger = logger.child({
|
|
28
33
|
name: this.appConfig.id
|
|
29
34
|
})
|
|
35
|
+
this.#telemetryConfig = telemetryConfig
|
|
30
36
|
}
|
|
31
37
|
|
|
32
38
|
getStatus () {
|
|
@@ -38,16 +44,11 @@ class PlatformaticApp {
|
|
|
38
44
|
}
|
|
39
45
|
|
|
40
46
|
async restart (force) {
|
|
41
|
-
if (this.#restarting) {
|
|
42
|
-
return
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
if (!this.#hotReload && !force) {
|
|
47
|
+
if (this.#restarting || !this.#started || (!this.#hotReload && !force)) {
|
|
46
48
|
return
|
|
47
49
|
}
|
|
48
50
|
|
|
49
51
|
this.#restarting = true
|
|
50
|
-
await this.stop()
|
|
51
52
|
|
|
52
53
|
/* c8 ignore next 4 - tests may not pass in a MessagePort. */
|
|
53
54
|
if (this.#loaderPort) {
|
|
@@ -55,7 +56,13 @@ class PlatformaticApp {
|
|
|
55
56
|
await once(this.#loaderPort, 'message')
|
|
56
57
|
}
|
|
57
58
|
|
|
58
|
-
|
|
59
|
+
this.#setuplogger(this.config.configManager)
|
|
60
|
+
try {
|
|
61
|
+
await this.server.restart()
|
|
62
|
+
} catch (err) {
|
|
63
|
+
this.#logAndExit(err)
|
|
64
|
+
}
|
|
65
|
+
|
|
59
66
|
this.#restarting = false
|
|
60
67
|
}
|
|
61
68
|
|
|
@@ -64,38 +71,37 @@ class PlatformaticApp {
|
|
|
64
71
|
throw new Error('application is already started')
|
|
65
72
|
}
|
|
66
73
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
74
|
+
this.#started = true
|
|
75
|
+
|
|
76
|
+
await this.#initializeConfig()
|
|
77
|
+
this.#originalWatch = this.config.configManager.current.watch
|
|
78
|
+
this.config.configManager.current.watch = false
|
|
79
|
+
|
|
70
80
|
const { configManager } = this.config
|
|
81
|
+
configManager.update({
|
|
82
|
+
...configManager.current,
|
|
83
|
+
telemetry: this.#telemetryConfig
|
|
84
|
+
})
|
|
71
85
|
const config = configManager.current
|
|
72
86
|
|
|
73
|
-
this.#originalWatch = config.watch
|
|
74
|
-
config.watch = false
|
|
75
87
|
this.#setuplogger(configManager)
|
|
76
88
|
|
|
77
89
|
try {
|
|
78
90
|
// If this is a restart, have the fastify server restart itself. If this
|
|
79
91
|
// is not a restart, then create a new server.
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
...config,
|
|
85
|
-
configManager
|
|
86
|
-
})
|
|
87
|
-
}
|
|
92
|
+
this.server = await buildServer({
|
|
93
|
+
...config,
|
|
94
|
+
configManager
|
|
95
|
+
})
|
|
88
96
|
} catch (err) {
|
|
89
97
|
this.#logAndExit(err)
|
|
90
98
|
}
|
|
91
99
|
|
|
92
|
-
if (config.plugins !== undefined
|
|
100
|
+
if (config.plugins !== undefined) {
|
|
93
101
|
this.#startFileWatching()
|
|
94
102
|
}
|
|
95
103
|
|
|
96
|
-
this
|
|
97
|
-
|
|
98
|
-
if (this.appConfig.entrypoint && !this.#restarting) {
|
|
104
|
+
if (this.appConfig.entrypoint) {
|
|
99
105
|
try {
|
|
100
106
|
await this.server.start()
|
|
101
107
|
/* c8 ignore next 5 */
|
|
@@ -111,11 +117,9 @@ class PlatformaticApp {
|
|
|
111
117
|
throw new Error('application has not been started')
|
|
112
118
|
}
|
|
113
119
|
|
|
114
|
-
if (!this.#restarting) {
|
|
115
|
-
await this.server.close()
|
|
116
|
-
}
|
|
117
|
-
|
|
118
120
|
await this.#stopFileWatching()
|
|
121
|
+
await this.server.close()
|
|
122
|
+
|
|
119
123
|
this.#started = false
|
|
120
124
|
}
|
|
121
125
|
|
|
@@ -199,11 +203,13 @@ class PlatformaticApp {
|
|
|
199
203
|
this.#hotReload = this.appConfig.hotReload
|
|
200
204
|
|
|
201
205
|
configManager.on('update', async (newConfig) => {
|
|
202
|
-
this.server
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
206
|
+
if (this.server) { // when we setup telemetry on config, we don't have a server yet
|
|
207
|
+
this.server.platformatic.config = newConfig
|
|
208
|
+
applyOverrides()
|
|
209
|
+
this.server.log.debug('config changed')
|
|
210
|
+
this.server.log.trace({ newConfig }, 'new config')
|
|
211
|
+
await this.restart()
|
|
212
|
+
}
|
|
207
213
|
})
|
|
208
214
|
|
|
209
215
|
configManager.on('error', (err) => {
|
|
@@ -221,6 +227,9 @@ class PlatformaticApp {
|
|
|
221
227
|
}
|
|
222
228
|
|
|
223
229
|
#startFileWatching () {
|
|
230
|
+
if (this.#fileWatcher) {
|
|
231
|
+
return
|
|
232
|
+
}
|
|
224
233
|
const server = this.server
|
|
225
234
|
const { configManager } = server.platformatic
|
|
226
235
|
// TODO FileWatcher and ConfigManager both watch the configuration file
|
|
@@ -233,27 +242,30 @@ class PlatformaticApp {
|
|
|
233
242
|
})
|
|
234
243
|
|
|
235
244
|
/* c8 ignore next 4 */
|
|
236
|
-
|
|
237
|
-
this.server.log.
|
|
245
|
+
const restart = debounce(() => {
|
|
246
|
+
this.server.log.info('files changed')
|
|
238
247
|
this.restart()
|
|
239
|
-
})
|
|
248
|
+
}, 100) // debounce restart for 100ms
|
|
249
|
+
fileWatcher.on('update', restart)
|
|
240
250
|
|
|
241
251
|
fileWatcher.startWatching()
|
|
242
252
|
server.log.debug('start watching files')
|
|
243
253
|
server.platformatic.fileWatcher = fileWatcher
|
|
244
254
|
server.platformatic.configManager.startWatching()
|
|
255
|
+
this.#fileWatcher = fileWatcher
|
|
245
256
|
}
|
|
246
257
|
|
|
247
258
|
async #stopFileWatching () {
|
|
248
|
-
const watcher = this.server.platformatic.fileWatcher
|
|
249
259
|
// The configManager automatically watches for the config file changes
|
|
250
260
|
// therefore we need to stop it all the times.
|
|
251
261
|
await this.config.configManager.stopWatching()
|
|
252
262
|
|
|
263
|
+
const watcher = this.#fileWatcher
|
|
253
264
|
if (watcher) {
|
|
254
265
|
this.server.log.debug('stop watching files')
|
|
255
266
|
await watcher.stopWatching()
|
|
256
267
|
this.server.platformatic.fileWatcher = undefined
|
|
268
|
+
this.#fileWatcher = null
|
|
257
269
|
}
|
|
258
270
|
}
|
|
259
271
|
|
package/lib/schema.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#! /usr/bin/env node
|
|
2
2
|
'use strict'
|
|
3
3
|
|
|
4
|
+
const telemetry = require('@platformatic/telemetry').schema
|
|
4
5
|
const pkg = require('../package.json')
|
|
5
6
|
const version = 'v' + pkg.version
|
|
6
7
|
const platformaticRuntimeSchema = {
|
|
@@ -42,6 +43,7 @@ const platformaticRuntimeSchema = {
|
|
|
42
43
|
}
|
|
43
44
|
}
|
|
44
45
|
},
|
|
46
|
+
telemetry,
|
|
45
47
|
services: {
|
|
46
48
|
type: 'array',
|
|
47
49
|
default: [],
|
package/lib/start.js
CHANGED
|
@@ -46,8 +46,12 @@ async function startWithConfig (configManager, env = process.env) {
|
|
|
46
46
|
env
|
|
47
47
|
})
|
|
48
48
|
|
|
49
|
+
let exited = null
|
|
49
50
|
worker.on('exit', () => {
|
|
50
51
|
configManager.fileWatcher?.stopWatching()
|
|
52
|
+
if (typeof exited === 'function') {
|
|
53
|
+
exited()
|
|
54
|
+
}
|
|
51
55
|
})
|
|
52
56
|
|
|
53
57
|
worker.on('error', () => {
|
|
@@ -65,8 +69,9 @@ async function startWithConfig (configManager, env = process.env) {
|
|
|
65
69
|
worker.postMessage({ signal: 'SIGUSR2' })
|
|
66
70
|
})
|
|
67
71
|
|
|
68
|
-
closeWithGrace((event) => {
|
|
72
|
+
closeWithGrace((event, cb) => {
|
|
69
73
|
worker.postMessage(event)
|
|
74
|
+
exited = cb
|
|
70
75
|
})
|
|
71
76
|
|
|
72
77
|
/* c8 ignore next 3 */
|
package/lib/unified-api.js
CHANGED
|
@@ -154,14 +154,6 @@ async function _start (args) {
|
|
|
154
154
|
}
|
|
155
155
|
|
|
156
156
|
async function startCommand (args) {
|
|
157
|
-
try {
|
|
158
|
-
await _start(args)
|
|
159
|
-
} catch (err) {
|
|
160
|
-
logErrorAndExit(err)
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
async function startCommandInRuntime (args) {
|
|
165
157
|
try {
|
|
166
158
|
const configType = await getConfigType(args)
|
|
167
159
|
const config = await _loadConfig({}, args, configType)
|
|
@@ -200,6 +192,5 @@ module.exports = {
|
|
|
200
192
|
loadConfig: _loadConfig,
|
|
201
193
|
start: _start,
|
|
202
194
|
startCommand,
|
|
203
|
-
startCommandInRuntime,
|
|
204
195
|
getApp
|
|
205
196
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@platformatic/runtime",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.33.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -24,13 +24,14 @@
|
|
|
24
24
|
"standard": "^17.1.0",
|
|
25
25
|
"tsd": "^0.28.1",
|
|
26
26
|
"typescript": "^5.1.6",
|
|
27
|
-
"@platformatic/sql-graphql": "0.
|
|
28
|
-
"@platformatic/sql-mapper": "0.
|
|
27
|
+
"@platformatic/sql-graphql": "0.33.0",
|
|
28
|
+
"@platformatic/sql-mapper": "0.33.0"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
31
|
"@hapi/topo": "^6.0.2",
|
|
32
32
|
"close-with-grace": "^1.2.0",
|
|
33
33
|
"commist": "^3.2.0",
|
|
34
|
+
"debounce": "^1.2.1",
|
|
34
35
|
"desm": "^1.3.0",
|
|
35
36
|
"es-main": "^1.2.0",
|
|
36
37
|
"fastest-levenshtein": "^1.0.16",
|
|
@@ -41,11 +42,12 @@
|
|
|
41
42
|
"pino": "^8.14.1",
|
|
42
43
|
"pino-pretty": "^10.0.0",
|
|
43
44
|
"undici": "^5.22.1",
|
|
44
|
-
"@platformatic/composer": "0.
|
|
45
|
-
"@platformatic/config": "0.
|
|
46
|
-
"@platformatic/db": "0.
|
|
47
|
-
"@platformatic/service": "0.
|
|
48
|
-
"@platformatic/
|
|
45
|
+
"@platformatic/composer": "0.33.0",
|
|
46
|
+
"@platformatic/config": "0.33.0",
|
|
47
|
+
"@platformatic/db": "0.33.0",
|
|
48
|
+
"@platformatic/service": "0.33.0",
|
|
49
|
+
"@platformatic/telemetry": "0.33.0",
|
|
50
|
+
"@platformatic/utils": "0.33.0"
|
|
49
51
|
},
|
|
50
52
|
"standard": {
|
|
51
53
|
"ignore": [
|
package/runtime.mjs
CHANGED
|
@@ -6,7 +6,7 @@ import { join } from 'desm'
|
|
|
6
6
|
import isMain from 'es-main'
|
|
7
7
|
import helpMe from 'help-me'
|
|
8
8
|
import parseArgs from 'minimist'
|
|
9
|
-
import {
|
|
9
|
+
import { startCommand } from './lib/unified-api.js'
|
|
10
10
|
import { compile as compileCmd } from './lib/compile.js'
|
|
11
11
|
|
|
12
12
|
export const compile = compileCmd
|
|
@@ -22,7 +22,7 @@ const program = commist({ maxDistance: 2 })
|
|
|
22
22
|
program.register('help', help.toStdout)
|
|
23
23
|
program.register('help start', help.toStdout.bind(null, ['start']))
|
|
24
24
|
program.register('help compile', help.toStdout.bind(null, ['compile']))
|
|
25
|
-
program.register('start',
|
|
25
|
+
program.register('start', startCommand)
|
|
26
26
|
program.register('compile', compile)
|
|
27
27
|
|
|
28
28
|
export async function run (argv) {
|
package/test/app.test.js
CHANGED
|
@@ -90,7 +90,7 @@ test('errors when stopping an already stopped application', async (t) => {
|
|
|
90
90
|
})
|
|
91
91
|
|
|
92
92
|
test('does not restart while restarting', async (t) => {
|
|
93
|
-
const { logger } = getLoggerAndStream()
|
|
93
|
+
const { logger, stream } = getLoggerAndStream()
|
|
94
94
|
const appPath = join(fixturesDir, 'monorepo', 'serviceApp')
|
|
95
95
|
const configFile = join(appPath, 'platformatic.service.json')
|
|
96
96
|
const config = {
|
|
@@ -105,17 +105,33 @@ test('does not restart while restarting', async (t) => {
|
|
|
105
105
|
}
|
|
106
106
|
const app = new PlatformaticApp(config, null, logger)
|
|
107
107
|
|
|
108
|
-
t.after(
|
|
108
|
+
t.after(async () => {
|
|
109
|
+
try {
|
|
110
|
+
await app.stop()
|
|
111
|
+
} catch {}
|
|
112
|
+
})
|
|
109
113
|
await app.start()
|
|
110
|
-
t.mock.method(app, 'stop')
|
|
111
114
|
await Promise.all([
|
|
112
115
|
app.restart(),
|
|
113
116
|
app.restart(),
|
|
114
117
|
app.restart()
|
|
115
118
|
])
|
|
119
|
+
await app.stop()
|
|
120
|
+
stream.end()
|
|
121
|
+
const lines = []
|
|
122
|
+
for await (const line of stream) {
|
|
123
|
+
lines.push(line)
|
|
124
|
+
}
|
|
116
125
|
|
|
117
|
-
|
|
118
|
-
|
|
126
|
+
let count = 0
|
|
127
|
+
for (const line of lines) {
|
|
128
|
+
// every time we restart we log listening
|
|
129
|
+
if (line.msg.match(/listening/)) {
|
|
130
|
+
count++
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
assert.strictEqual(count, 2)
|
|
119
135
|
})
|
|
120
136
|
|
|
121
137
|
test('restarts on SIGUSR2', async (t) => {
|
package/test/cli/helper.mjs
CHANGED
|
@@ -35,12 +35,14 @@ export async function start (...args) {
|
|
|
35
35
|
|
|
36
36
|
for await (const messages of on(output, 'data')) {
|
|
37
37
|
for (const message of messages) {
|
|
38
|
-
|
|
39
|
-
message.
|
|
38
|
+
if (message.msg) {
|
|
39
|
+
const url = message.url ??
|
|
40
|
+
message.msg.match(/server listening at (.+)/i)?.[1]
|
|
40
41
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
42
|
+
if (url !== undefined) {
|
|
43
|
+
clearTimeout(errorTimeout)
|
|
44
|
+
return { child, url, output }
|
|
45
|
+
}
|
|
44
46
|
}
|
|
45
47
|
}
|
|
46
48
|
}
|
package/test/cli/start.test.mjs
CHANGED
|
@@ -74,7 +74,7 @@ test('does not start if node inspector flags are provided', async (t) => {
|
|
|
74
74
|
for (const message of messages) {
|
|
75
75
|
stderr += message
|
|
76
76
|
|
|
77
|
-
if (/
|
|
77
|
+
if (/The Node.js inspector flags are not supported/.test(stderr)) {
|
|
78
78
|
found = true
|
|
79
79
|
break
|
|
80
80
|
}
|
package/test/cli/watch.test.mjs
CHANGED
|
@@ -47,9 +47,13 @@ function createEsmLoggingPlugin (text, reloaded) {
|
|
|
47
47
|
`
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
+
function saferm (path) {
|
|
51
|
+
return rm(path, { recursive: true, force: true }).catch(() => {})
|
|
52
|
+
}
|
|
53
|
+
|
|
50
54
|
test('watches CommonJS files', async (t) => {
|
|
51
55
|
const tmpDir = await mkdtemp(join(base, 'watch-'))
|
|
52
|
-
t.after(() =>
|
|
56
|
+
t.after(() => saferm(tmpDir))
|
|
53
57
|
t.diagnostic(`using ${tmpDir}`)
|
|
54
58
|
const configFileSrc = join(fixturesDir, 'configs', 'monorepo.json')
|
|
55
59
|
const configFileDst = join(tmpDir, 'configs', 'monorepo.json')
|
|
@@ -65,8 +69,6 @@ test('watches CommonJS files', async (t) => {
|
|
|
65
69
|
await writeFile(cjsPluginFilePath, createCjsLoggingPlugin('v1', false))
|
|
66
70
|
const { child } = await start('-c', configFileDst)
|
|
67
71
|
t.after(() => child.kill('SIGINT'))
|
|
68
|
-
child.stdout.pipe(process.stderr)
|
|
69
|
-
child.stderr.pipe(process.stderr)
|
|
70
72
|
|
|
71
73
|
await writeFile(cjsPluginFilePath, createCjsLoggingPlugin('v2', true))
|
|
72
74
|
|
|
@@ -79,7 +81,7 @@ test('watches CommonJS files', async (t) => {
|
|
|
79
81
|
|
|
80
82
|
test('watches ESM files', async (t) => {
|
|
81
83
|
const tmpDir = await mkdtemp(join(base, 'watch-'))
|
|
82
|
-
t.after(() =>
|
|
84
|
+
t.after(() => saferm(tmpDir))
|
|
83
85
|
t.diagnostic(`using ${tmpDir}`)
|
|
84
86
|
const configFileSrc = join(fixturesDir, 'configs', 'monorepo.json')
|
|
85
87
|
const configFileDst = join(tmpDir, 'configs', 'monorepo.json')
|
|
@@ -95,8 +97,6 @@ test('watches ESM files', async (t) => {
|
|
|
95
97
|
await writeFile(esmPluginFilePath, createEsmLoggingPlugin('v1', false))
|
|
96
98
|
const { child } = await start('-c', configFileDst)
|
|
97
99
|
t.after(() => child.kill('SIGINT'))
|
|
98
|
-
child.stdout.pipe(process.stderr)
|
|
99
|
-
child.stderr.pipe(process.stderr)
|
|
100
100
|
await writeFile(esmPluginFilePath, createEsmLoggingPlugin('v2', true))
|
|
101
101
|
|
|
102
102
|
for await (const log of child.ndj) {
|
|
@@ -108,7 +108,7 @@ test('watches ESM files', async (t) => {
|
|
|
108
108
|
|
|
109
109
|
test('should not hot reload files with `--hot-reload false', async (t) => {
|
|
110
110
|
const tmpDir = await mkdtemp(join(base, 'watch-'))
|
|
111
|
-
t.after(() =>
|
|
111
|
+
t.after(() => saferm(tmpDir))
|
|
112
112
|
t.diagnostic(`using ${tmpDir}`)
|
|
113
113
|
const configFileSrc = join(fixturesDir, 'configs', 'monorepo.json')
|
|
114
114
|
const configFileDst = join(tmpDir, 'configs', 'monorepo.json')
|
|
@@ -124,11 +124,84 @@ test('should not hot reload files with `--hot-reload false', async (t) => {
|
|
|
124
124
|
await writeFile(cjsPluginFilePath, createCjsLoggingPlugin('v1', false))
|
|
125
125
|
const { child, url } = await start('-c', configFileDst, '--hot-reload', 'false')
|
|
126
126
|
t.after(() => child.kill('SIGINT'))
|
|
127
|
-
child.stdout.pipe(process.stderr)
|
|
128
|
-
child.stderr.pipe(process.stderr)
|
|
129
127
|
await writeFile(cjsPluginFilePath, createCjsLoggingPlugin('v2', true))
|
|
130
128
|
await sleep(5000)
|
|
131
129
|
const res = await request(`${url}/version`)
|
|
132
130
|
const version = await res.body.text()
|
|
133
131
|
assert.strictEqual(version, 'v1')
|
|
134
132
|
})
|
|
133
|
+
|
|
134
|
+
test('watches CommonJS files with hotreload', { timeout: 30000, skip: process.env.CI }, async (t) => {
|
|
135
|
+
const tmpDir = await mkdtemp(join(base, 'watch-'))
|
|
136
|
+
t.after(() => saferm(tmpDir))
|
|
137
|
+
t.diagnostic(`using ${tmpDir}`)
|
|
138
|
+
const configFileSrc = join(fixturesDir, 'configs', 'hotreload.json')
|
|
139
|
+
const configFileDst = join(tmpDir, 'configs', 'monorepo.json')
|
|
140
|
+
const appSrc = join(fixturesDir, 'monorepo')
|
|
141
|
+
const appDst = join(tmpDir, 'monorepo')
|
|
142
|
+
const cjsPluginFilePath = join(appDst, 'serviceAppWithLogger', 'plugin.js')
|
|
143
|
+
|
|
144
|
+
await Promise.all([
|
|
145
|
+
cp(configFileSrc, configFileDst),
|
|
146
|
+
cp(appSrc, appDst, { recursive: true })
|
|
147
|
+
])
|
|
148
|
+
|
|
149
|
+
await writeFile(cjsPluginFilePath, createCjsLoggingPlugin('v1', false))
|
|
150
|
+
const { child } = await start('-c', configFileDst)
|
|
151
|
+
t.after(() => child.kill('SIGINT'))
|
|
152
|
+
|
|
153
|
+
await writeFile(cjsPluginFilePath, createCjsLoggingPlugin('v2', true))
|
|
154
|
+
|
|
155
|
+
let restartedSecondTime = false
|
|
156
|
+
let restartedThirdTime = false
|
|
157
|
+
|
|
158
|
+
for await (const log of child.ndj) {
|
|
159
|
+
if (log.msg === 'RELOADED v2') {
|
|
160
|
+
restartedSecondTime = true
|
|
161
|
+
} else if (log.msg === 'RELOADED v3') {
|
|
162
|
+
restartedThirdTime = true
|
|
163
|
+
break
|
|
164
|
+
} else if (log.msg?.match(/watching/)) {
|
|
165
|
+
await writeFile(cjsPluginFilePath, createCjsLoggingPlugin('v3', true))
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
assert.ok(restartedSecondTime)
|
|
170
|
+
assert.ok(restartedThirdTime)
|
|
171
|
+
})
|
|
172
|
+
|
|
173
|
+
test('watches CommonJS files with hotreload on a single service', { timeout: 30000, skip: process.env.CI }, async (t) => {
|
|
174
|
+
const tmpDir = await mkdtemp(join(base, 'watch-'))
|
|
175
|
+
t.after(() => saferm(tmpDir))
|
|
176
|
+
t.diagnostic(`using ${tmpDir}`)
|
|
177
|
+
const appSrc = join(fixturesDir, 'monorepo', 'serviceAppWithLogger')
|
|
178
|
+
const appDst = join(tmpDir)
|
|
179
|
+
const cjsPluginFilePath = join(appDst, 'plugin.js')
|
|
180
|
+
|
|
181
|
+
await Promise.all([
|
|
182
|
+
cp(appSrc, appDst, { recursive: true })
|
|
183
|
+
])
|
|
184
|
+
|
|
185
|
+
await writeFile(cjsPluginFilePath, createCjsLoggingPlugin('v1', false))
|
|
186
|
+
const { child } = await start('-c', join(appDst, 'platformatic.service.json'))
|
|
187
|
+
t.after(() => child.kill('SIGINT'))
|
|
188
|
+
|
|
189
|
+
await writeFile(cjsPluginFilePath, createCjsLoggingPlugin('v2', true))
|
|
190
|
+
|
|
191
|
+
let restartedSecondTime = false
|
|
192
|
+
let restartedThirdTime = false
|
|
193
|
+
|
|
194
|
+
for await (const log of child.ndj) {
|
|
195
|
+
if (log.msg === 'RELOADED v2') {
|
|
196
|
+
restartedSecondTime = true
|
|
197
|
+
} else if (log.msg === 'RELOADED v3') {
|
|
198
|
+
assert.ok(restartedSecondTime)
|
|
199
|
+
restartedThirdTime = true
|
|
200
|
+
break
|
|
201
|
+
} else if (log.msg?.match(/listening/)) {
|
|
202
|
+
await writeFile(cjsPluginFilePath, createCjsLoggingPlugin('v3', true))
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
assert.ok(restartedThirdTime)
|
|
207
|
+
})
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const assert = require('node:assert')
|
|
4
|
+
const { request } = require('undici')
|
|
5
|
+
const { test } = require('node:test')
|
|
6
|
+
const { join } = require('node:path')
|
|
7
|
+
const { loadConfig } = require('@platformatic/service')
|
|
8
|
+
const { platformaticRuntime } = require('..')
|
|
9
|
+
const { startWithConfig } = require('../lib/start')
|
|
10
|
+
const fixturesDir = join(__dirname, '..', 'fixtures')
|
|
11
|
+
|
|
12
|
+
test('propagate the traceId correctly to runtime services', async (t) => {
|
|
13
|
+
const configFile = join(fixturesDir, 'telemetry', 'platformatic.runtime.json')
|
|
14
|
+
const config = await loadConfig({}, ['-c', configFile], platformaticRuntime)
|
|
15
|
+
const app = await startWithConfig(config.configManager)
|
|
16
|
+
|
|
17
|
+
t.after(async () => {
|
|
18
|
+
await app.close()
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
const entryUrl = await app.start()
|
|
22
|
+
|
|
23
|
+
const traceId = '5e994e8fb53b27c91dcd2fec22771d15'
|
|
24
|
+
const spanId = '166f3ab30f21800b'
|
|
25
|
+
const traceparent = `00-${traceId}-${spanId}-01`
|
|
26
|
+
const res = await request(entryUrl, {
|
|
27
|
+
method: 'GET',
|
|
28
|
+
path: '/',
|
|
29
|
+
headers: {
|
|
30
|
+
traceparent
|
|
31
|
+
}
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
assert.strictEqual(res.statusCode, 200)
|
|
35
|
+
const response = await res.body.json()
|
|
36
|
+
assert.strictEqual(response.traceId, traceId)
|
|
37
|
+
})
|
package/test/unified-api.test.js
CHANGED
|
@@ -254,7 +254,6 @@ test('start()', async (t) => {
|
|
|
254
254
|
const scriptFile = join(fixturesDir, 'starter.js')
|
|
255
255
|
const configFile = join(fixturesDir, 'monorepo', 'serviceAppWithLogger', 'platformatic.service.json')
|
|
256
256
|
const child = spawn(process.execPath, [scriptFile, configFile])
|
|
257
|
-
child.stdout.pipe(process.stdout)
|
|
258
257
|
child.stderr.pipe(process.stderr)
|
|
259
258
|
const [exitCode] = await once(child, 'exit')
|
|
260
259
|
|
|
@@ -318,14 +317,11 @@ test('startCommand()', async (t) => {
|
|
|
318
317
|
|
|
319
318
|
assert.strictEqual(exitCode, 42)
|
|
320
319
|
})
|
|
321
|
-
})
|
|
322
320
|
|
|
323
|
-
test('startCommandInRuntime()', async (t) => {
|
|
324
321
|
await t.test('can start a non-runtime application', async (t) => {
|
|
325
322
|
const scriptFile = join(fixturesDir, 'start-command-in-runtime.js')
|
|
326
323
|
const configFile = join(fixturesDir, 'monorepo', 'serviceAppWithLogger', 'platformatic.service.json')
|
|
327
324
|
const child = spawn(process.execPath, [scriptFile, configFile])
|
|
328
|
-
child.stdout.pipe(process.stdout)
|
|
329
325
|
child.stderr.pipe(process.stderr)
|
|
330
326
|
const [exitCode] = await once(child, 'exit')
|
|
331
327
|
|
|
@@ -336,7 +332,6 @@ test('startCommandInRuntime()', async (t) => {
|
|
|
336
332
|
const scriptFile = join(fixturesDir, 'start-command-in-runtime.js')
|
|
337
333
|
const configFile = join(fixturesDir, 'configs', 'monorepo.json')
|
|
338
334
|
const child = spawn(process.execPath, [scriptFile, configFile])
|
|
339
|
-
child.stdout.pipe(process.stdout)
|
|
340
335
|
child.stderr.pipe(process.stderr)
|
|
341
336
|
const [exitCode] = await once(child, 'exit')
|
|
342
337
|
|