@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.
@@ -0,0 +1,2 @@
1
+ 'use strict'
2
+ module.exports = Math.random()
@@ -0,0 +1,3 @@
1
+ {
2
+ "main": "foo.js"
3
+ }
@@ -0,0 +1 @@
1
+ export default Math.random()
@@ -0,0 +1,4 @@
1
+ {
2
+ "main": "foom.js",
3
+ "type": "module"
4
+ }
@@ -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
- await Promise.allSettled(this.#services.values().map(async (service) => {
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
@@ -148,6 +148,7 @@ class PlatformaticApp {
148
148
 
149
149
  if (this.#started) {
150
150
  await this.stop()
151
+ this.server.log.info('server stopped')
151
152
  }
152
153
  }
153
154
 
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
- delete require.cache[key]
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
- throw err
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
- throw err
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.33.1",
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.33.1",
28
- "@platformatic/sql-mapper": "0.33.1"
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.33.1",
46
- "@platformatic/config": "0.33.1",
47
- "@platformatic/db": "0.33.1",
48
- "@platformatic/service": "0.33.1",
49
- "@platformatic/telemetry": "0.33.1",
50
- "@platformatic/utils": "0.33.1"
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": [
@@ -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
+ })