@platformatic/runtime 0.33.1 → 0.34.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/do-not-reload-dependencies/node_modules/foo/foo.js +2 -0
- package/fixtures/do-not-reload-dependencies/node_modules/foo/package.json +3 -0
- package/fixtures/do-not-reload-dependencies/node_modules/foom/foom.js +1 -0
- package/fixtures/do-not-reload-dependencies/node_modules/foom/package.json +4 -0
- package/fixtures/do-not-reload-dependencies/platformatic.service.json +18 -0
- package/fixtures/do-not-reload-dependencies/plugin.js +14 -0
- package/lib/api.js +10 -1
- package/lib/app.js +1 -0
- package/lib/loader.mjs +4 -2
- package/lib/worker.js +6 -2
- package/package.json +9 -9
- package/test/cli/watch.test.mjs +78 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default Math.random()
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://platformatic.dev/schemas/v0.33.1/service",
|
|
3
|
+
"server": {
|
|
4
|
+
"hostname": "127.0.0.1",
|
|
5
|
+
"port": "{PORT}",
|
|
6
|
+
"logger": {
|
|
7
|
+
"level": "info"
|
|
8
|
+
}
|
|
9
|
+
},
|
|
10
|
+
"service": {
|
|
11
|
+
"openapi": true
|
|
12
|
+
},
|
|
13
|
+
"plugins": {
|
|
14
|
+
"paths": [
|
|
15
|
+
"./plugin.js"
|
|
16
|
+
]
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
module.exports = function (fastify, opts, next) {
|
|
4
|
+
fastify.get('/plugin1', function (request, reply) {
|
|
5
|
+
const foo = require('foo')
|
|
6
|
+
reply.send({ hello: foo })
|
|
7
|
+
})
|
|
8
|
+
|
|
9
|
+
fastify.get('/plugin2', async function (request, reply) {
|
|
10
|
+
const foom = (await import('foom')).default
|
|
11
|
+
return { hello: foom }
|
|
12
|
+
})
|
|
13
|
+
next()
|
|
14
|
+
}
|
package/lib/api.js
CHANGED
|
@@ -49,9 +49,18 @@ class RuntimeApi {
|
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
async #handleProcessLevelEvent (message) {
|
|
52
|
-
|
|
52
|
+
const services = [...this.#services.values()]
|
|
53
|
+
await Promise.allSettled(services.map(async (service) => {
|
|
53
54
|
await service.handleProcessLevelEvent(message)
|
|
54
55
|
}))
|
|
56
|
+
|
|
57
|
+
for (const service of services) {
|
|
58
|
+
if (service.getStatus() === 'started') {
|
|
59
|
+
return
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
process.exit() // Exit the worker thread if all services are stopped
|
|
55
64
|
}
|
|
56
65
|
|
|
57
66
|
async #executeCommand (message) {
|
package/lib/app.js
CHANGED
package/lib/loader.mjs
CHANGED
|
@@ -20,7 +20,9 @@ function clearCjsCache () {
|
|
|
20
20
|
// the entire require() cache. See the DEP0144 documentation for how to do
|
|
21
21
|
// it.
|
|
22
22
|
Object.keys(require.cache).forEach((key) => {
|
|
23
|
-
|
|
23
|
+
if (!key.match(/node_modules/)) {
|
|
24
|
+
delete require.cache[key]
|
|
25
|
+
}
|
|
24
26
|
})
|
|
25
27
|
}
|
|
26
28
|
|
|
@@ -89,7 +91,7 @@ export async function resolve (specifier, context, nextResolve) {
|
|
|
89
91
|
|
|
90
92
|
// If the specifier could not be mapped to a file, or the path is this file,
|
|
91
93
|
// then don't do anything.
|
|
92
|
-
if (typeof url !== 'string' || url === import.meta.url) {
|
|
94
|
+
if (typeof url !== 'string' || url === import.meta.url || url.match(/node_modules/)) {
|
|
93
95
|
return nextResolve(specifier, context)
|
|
94
96
|
}
|
|
95
97
|
|
package/lib/worker.js
CHANGED
|
@@ -32,14 +32,18 @@ const logger = pino(transport, destination)
|
|
|
32
32
|
/* c8 ignore next 4 */
|
|
33
33
|
process.once('uncaughtException', (err) => {
|
|
34
34
|
logger.error({ err }, 'runtime error')
|
|
35
|
-
|
|
35
|
+
setImmediate(() => {
|
|
36
|
+
process.exit(1)
|
|
37
|
+
})
|
|
36
38
|
})
|
|
37
39
|
|
|
38
40
|
// Tested by test/cli/start.test.mjs by C8 does not see it.
|
|
39
41
|
/* c8 ignore next 4 */
|
|
40
42
|
process.once('unhandledRejection', (err) => {
|
|
41
43
|
logger.error({ err }, 'runtime error')
|
|
42
|
-
|
|
44
|
+
setImmediate(() => {
|
|
45
|
+
process.exit(1)
|
|
46
|
+
})
|
|
43
47
|
})
|
|
44
48
|
|
|
45
49
|
function main () {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@platformatic/runtime",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.34.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -24,8 +24,8 @@
|
|
|
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.34.0",
|
|
28
|
+
"@platformatic/sql-mapper": "0.34.0"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
31
|
"@hapi/topo": "^6.0.2",
|
|
@@ -42,12 +42,12 @@
|
|
|
42
42
|
"pino": "^8.14.1",
|
|
43
43
|
"pino-pretty": "^10.0.0",
|
|
44
44
|
"undici": "^5.22.1",
|
|
45
|
-
"@platformatic/composer": "0.
|
|
46
|
-
"@platformatic/config": "0.
|
|
47
|
-
"@platformatic/db": "0.
|
|
48
|
-
"@platformatic/service": "0.
|
|
49
|
-
"@platformatic/telemetry": "0.
|
|
50
|
-
"@platformatic/utils": "0.
|
|
45
|
+
"@platformatic/composer": "0.34.0",
|
|
46
|
+
"@platformatic/config": "0.34.0",
|
|
47
|
+
"@platformatic/db": "0.34.0",
|
|
48
|
+
"@platformatic/service": "0.34.0",
|
|
49
|
+
"@platformatic/telemetry": "0.34.0",
|
|
50
|
+
"@platformatic/utils": "0.34.0"
|
|
51
51
|
},
|
|
52
52
|
"standard": {
|
|
53
53
|
"ignore": [
|
package/test/cli/watch.test.mjs
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import assert from 'node:assert'
|
|
2
|
-
import { cp, writeFile, mkdtemp, mkdir, rm } from 'node:fs/promises'
|
|
2
|
+
import { cp, writeFile, mkdtemp, mkdir, rm, utimes } from 'node:fs/promises'
|
|
3
3
|
import { join } from 'node:path'
|
|
4
4
|
import { test } from 'node:test'
|
|
5
5
|
import { setTimeout as sleep } from 'node:timers/promises'
|
|
6
6
|
import desm from 'desm'
|
|
7
7
|
import { request } from 'undici'
|
|
8
8
|
import { start } from './helper.mjs'
|
|
9
|
+
import { on } from 'node:events'
|
|
9
10
|
|
|
10
11
|
const fixturesDir = join(desm(import.meta.url), '..', '..', 'fixtures')
|
|
11
12
|
|
|
@@ -205,3 +206,79 @@ test('watches CommonJS files with hotreload on a single service', { timeout: 300
|
|
|
205
206
|
|
|
206
207
|
assert.ok(restartedThirdTime)
|
|
207
208
|
})
|
|
209
|
+
|
|
210
|
+
test('do not hot reload dependencies', { timeout: 30000, skip: process.env.CI }, async (t) => {
|
|
211
|
+
process.env.PORT = 0
|
|
212
|
+
const config = join(fixturesDir, 'do-not-reload-dependencies', 'platformatic.service.json')
|
|
213
|
+
const { child, url } = await start('-c', config)
|
|
214
|
+
t.after(() => child.kill('SIGINT'))
|
|
215
|
+
t.after(() => delete process.env.PORT)
|
|
216
|
+
|
|
217
|
+
const res1 = await request(`${url}/plugin1`)
|
|
218
|
+
const plugin1 = (await res1.body.json()).hello
|
|
219
|
+
|
|
220
|
+
const res2 = await request(`${url}/plugin2`)
|
|
221
|
+
const plugin2 = (await res2.body.json()).hello
|
|
222
|
+
|
|
223
|
+
utimes(config, new Date(), new Date()).catch(() => {})
|
|
224
|
+
|
|
225
|
+
// wait for restart
|
|
226
|
+
for await (const messages of on(child.ndj, 'data')) {
|
|
227
|
+
let url
|
|
228
|
+
for (const message of messages) {
|
|
229
|
+
if (message.msg) {
|
|
230
|
+
url = message.msg.match(/server listening at (.+)/i)?.[1]
|
|
231
|
+
|
|
232
|
+
if (url !== undefined) {
|
|
233
|
+
break
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
if (url !== undefined) {
|
|
239
|
+
break
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
const res3 = await request(`${url}/plugin1`)
|
|
244
|
+
assert.strictEqual((await res3.body.json()).hello, plugin1)
|
|
245
|
+
|
|
246
|
+
const res4 = await request(`${url}/plugin2`)
|
|
247
|
+
assert.strictEqual((await res4.body.json()).hello, plugin2)
|
|
248
|
+
})
|
|
249
|
+
|
|
250
|
+
test('watches CommonJS files with hotreload on a single service', { timeout: 30000, skip: process.env.CI }, async (t) => {
|
|
251
|
+
const tmpDir = await mkdtemp(join(base, 'watch-'))
|
|
252
|
+
t.after(() => saferm(tmpDir))
|
|
253
|
+
t.diagnostic(`using ${tmpDir}`)
|
|
254
|
+
const appSrc = join(fixturesDir, 'monorepo', 'serviceAppWithLogger')
|
|
255
|
+
const appDst = join(tmpDir)
|
|
256
|
+
const cjsPluginFilePath = join(appDst, 'plugin.js')
|
|
257
|
+
|
|
258
|
+
await Promise.all([
|
|
259
|
+
cp(appSrc, appDst, { recursive: true })
|
|
260
|
+
])
|
|
261
|
+
|
|
262
|
+
await writeFile(cjsPluginFilePath, createCjsLoggingPlugin('v1', false))
|
|
263
|
+
const { child } = await start('-c', join(appDst, 'platformatic.service.json'))
|
|
264
|
+
t.after(() => child.kill('SIGINT'))
|
|
265
|
+
|
|
266
|
+
await writeFile(cjsPluginFilePath, createCjsLoggingPlugin('v2', true))
|
|
267
|
+
|
|
268
|
+
let restartedSecondTime = false
|
|
269
|
+
let restartedThirdTime = false
|
|
270
|
+
|
|
271
|
+
for await (const log of child.ndj) {
|
|
272
|
+
if (log.msg === 'RELOADED v2') {
|
|
273
|
+
restartedSecondTime = true
|
|
274
|
+
} else if (log.msg === 'RELOADED v3') {
|
|
275
|
+
assert.ok(restartedSecondTime)
|
|
276
|
+
restartedThirdTime = true
|
|
277
|
+
break
|
|
278
|
+
} else if (log.msg?.match(/listening/)) {
|
|
279
|
+
await writeFile(cjsPluginFilePath, createCjsLoggingPlugin('v3', true))
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
assert.ok(restartedThirdTime)
|
|
284
|
+
})
|