@platformatic/runtime 3.37.0 → 3.38.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/index.js CHANGED
@@ -146,7 +146,12 @@ export async function create (configOrRoot, sourceOrConfig, context) {
146
146
  if (context?.start) {
147
147
  let port = config.server?.port
148
148
 
149
- await runtime.init()
149
+ try {
150
+ await runtime.init()
151
+ } catch (err) {
152
+ await runtime.close()
153
+ throw err
154
+ }
150
155
 
151
156
  if (context.reloaded) {
152
157
  runtime.logger.info('The application has been successfully reloaded.')
package/lib/errors.js CHANGED
@@ -1,5 +1,14 @@
1
1
  import createError from '@fastify/error'
2
2
 
3
+ // Keep in sync with packages/basic/lib/errors.js
4
+ export const exitCodes = {
5
+ MANAGER_MESSAGE_HANDLING_FAILED: 11,
6
+ MANAGER_SOCKET_ERROR: 11,
7
+ PROCESS_UNHANDLED_ERROR: 20,
8
+ PROCESS_MESSAGE_HANDLING_FAILED: 21,
9
+ PROCESS_SOCKET_ERROR: 22
10
+ }
11
+
3
12
  export const ERROR_PREFIX = 'PLT_RUNTIME'
4
13
 
5
14
  export const AddressInUseError = createError(
package/lib/generator.js CHANGED
@@ -113,6 +113,10 @@ export class RuntimeGenerator extends BaseGenerator {
113
113
  template.workspaces = [this.applicationsFolder + '/*']
114
114
  }
115
115
 
116
+ if (this.packageManager === 'yarn') {
117
+ template.private = true
118
+ }
119
+
116
120
  return template
117
121
  }
118
122
 
package/lib/runtime.js CHANGED
@@ -1608,7 +1608,7 @@ export class Runtime extends EventEmitter {
1608
1608
  this.emitAndNotify('application:init', id)
1609
1609
  }
1610
1610
 
1611
- async #setupWorker (config, applicationConfig, workersCount, applicationId, index, enabled = true) {
1611
+ async #setupWorker (config, applicationConfig, workersCount, applicationId, index, enabled = true, attempt = 0) {
1612
1612
  const { restartOnError } = config
1613
1613
  const workerId = `${applicationId}:${index}`
1614
1614
 
@@ -1854,12 +1854,21 @@ export class Runtime extends EventEmitter {
1854
1854
  try {
1855
1855
  await waitEventFromITC(worker, 'init')
1856
1856
  } catch (e) {
1857
+ if (attempt === MAX_BOOTSTRAP_ATTEMPTS) {
1858
+ const error = new RuntimeAbortedError({ cause: e })
1859
+ error.message = `Unable to initialize the ${errorLabel}.`
1860
+ throw e
1861
+ }
1862
+
1857
1863
  if (e.code !== 'PLT_RUNTIME_APPLICATION_WORKER_EXIT') {
1858
- this.logger.error({ err: ensureLoggableError(e) }, `Failed to initialize the ${errorLabel}. Replacing it ...`)
1864
+ this.logger.error(
1865
+ { err: ensureLoggableError(e) },
1866
+ `Failed to initialize the ${errorLabel}. Attempting to initialize a new worker ...`
1867
+ )
1859
1868
  }
1860
1869
 
1861
1870
  this.#workers.delete(workerId)
1862
- return this.#setupWorker(config, applicationConfig, workersCount, applicationId, index, enabled)
1871
+ return this.#setupWorker(config, applicationConfig, workersCount, applicationId, index, enabled, attempt + 1)
1863
1872
  }
1864
1873
 
1865
1874
  if (applicationConfig.entrypoint) {
@@ -100,7 +100,7 @@ export class Controller extends EventEmitter {
100
100
  }
101
101
 
102
102
  // Note: capability's init() is executed within start
103
- async init () {
103
+ async init (cleanupHandlers) {
104
104
  try {
105
105
  const appConfig = this.applicationConfig
106
106
 
@@ -133,6 +133,10 @@ export class Controller extends EventEmitter {
133
133
 
134
134
  this.#updateDispatcher()
135
135
 
136
+ if (cleanupHandlers) {
137
+ cleanupHandlers()
138
+ }
139
+
136
140
  if (this.capability.exitOnUnhandledErrors && this.runtimeConfig.exitOnUnhandledErrors) {
137
141
  this.#setupHandlers()
138
142
  }
package/lib/worker/itc.js CHANGED
@@ -14,7 +14,8 @@ import {
14
14
  FailedToRetrieveMetaError,
15
15
  FailedToRetrieveMetricsError,
16
16
  FailedToRetrieveOpenAPISchemaError,
17
- WorkerExitedError
17
+ WorkerExitedError,
18
+ exitCodes
18
19
  } from '../errors.js'
19
20
  import { updateUndiciInterceptors } from './interceptors.js'
20
21
  import { MessagingITC } from './messaging.js'
@@ -86,7 +87,7 @@ async function safeHandleInITC (worker, fn) {
86
87
  ])
87
88
 
88
89
  if (typeof exitCode === 'number') {
89
- if (typeof worker[kWorkerId] !== 'undefined') {
90
+ if (typeof worker[kWorkerId] !== 'undefined' && exitCode !== exitCodes.PROCESS_UNHANDLED_ERROR) {
90
91
  throw new WorkerExitedError(worker[kWorkerId], worker[kApplicationId], exitCode)
91
92
  } else {
92
93
  throw new ApplicationExitedError(worker[kId], exitCode)
@@ -2,6 +2,7 @@ import {
2
2
  buildPinoFormatters,
3
3
  buildPinoTimestamp,
4
4
  disablePinoDirectWrite,
5
+ ensureLoggableError,
5
6
  getPrivateSymbol
6
7
  } from '@platformatic/foundation'
7
8
  import { subscribe } from 'node:diagnostics_channel'
@@ -14,12 +15,22 @@ import { pathToFileURL } from 'node:url'
14
15
  import { threadId, workerData } from 'node:worker_threads'
15
16
  import pino from 'pino'
16
17
  import { install as installUndiciGlobals } from 'undici'
18
+ import { exitCodes } from '../errors.js'
17
19
  import { Controller } from './controller.js'
20
+ import { initHealthSignalsApi } from './health-signals.js'
18
21
  import { setDispatcher } from './interceptors.js'
19
22
  import { setupITC } from './itc.js'
20
23
  import { SharedContext } from './shared-context.js'
21
24
  import { kId, kITC, kStderrMarker } from './symbols.js'
22
- import { initHealthSignalsApi } from './health-signals.js'
25
+
26
+ function handlePreInitializationUnhandled (type, err) {
27
+ const label = `worker ${workerData.worker.index} of the application "${workerData.applicationConfig.id}"`
28
+ globalThis.platformatic.logger.error(
29
+ { err: ensureLoggableError(err) },
30
+ `The ${label} threw an ${type} before initialization.`
31
+ )
32
+ process.exit(exitCodes.PROCESS_UNHANDLED_ERROR)
33
+ }
23
34
 
24
35
  class ForwardingEventEmitter extends EventEmitter {
25
36
  emitAndNotify (event, ...args) {
@@ -50,6 +61,18 @@ function patchLogging () {
50
61
  }
51
62
  }
52
63
 
64
+ function setupHandlers () {
65
+ const unhandledExceptionHandler = handlePreInitializationUnhandled.bind(null, 'uncaught exception')
66
+ const unhandledRejectionHandler = handlePreInitializationUnhandled.bind(null, 'uncaught rejection')
67
+ process.on('uncaughtException', unhandledExceptionHandler)
68
+ process.on('unhandledRejection', unhandledRejectionHandler)
69
+
70
+ return () => {
71
+ process.removeListener('uncaughtException', unhandledExceptionHandler)
72
+ process.removeListener('unhandledRejection', unhandledRejectionHandler)
73
+ }
74
+ }
75
+
53
76
  function createLogger () {
54
77
  // Do not propagate runtime transports to the worker
55
78
  if (workerData.config.logger) {
@@ -137,6 +160,8 @@ async function setupCompileCache (runtimeConfig, applicationConfig, logger) {
137
160
  }
138
161
 
139
162
  async function main () {
163
+ const cleanup = setupHandlers()
164
+
140
165
  installUndiciGlobals(globalThis)
141
166
  globalThis[kId] = threadId
142
167
  globalThis.platformatic = Object.assign(globalThis.platformatic ?? {}, {
@@ -224,7 +249,7 @@ async function main () {
224
249
  metricsConfig
225
250
  )
226
251
 
227
- await controller.init()
252
+ await controller.init(cleanup)
228
253
 
229
254
  if (applicationConfig.entrypoint && runtimeConfig.basePath) {
230
255
  const meta = await controller.capability.getMeta()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@platformatic/runtime",
3
- "version": "3.37.0",
3
+ "version": "3.38.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.37.0",
39
- "@platformatic/db": "3.37.0",
40
- "@platformatic/gateway": "3.37.0",
41
- "@platformatic/node": "3.37.0",
42
- "@platformatic/sql-graphql": "3.37.0",
43
- "@platformatic/service": "3.37.0",
44
- "@platformatic/sql-mapper": "3.37.0",
45
- "@platformatic/wattpm-pprof-capture": "3.37.0"
38
+ "@platformatic/db": "3.38.0",
39
+ "@platformatic/composer": "3.38.0",
40
+ "@platformatic/gateway": "3.38.0",
41
+ "@platformatic/node": "3.38.0",
42
+ "@platformatic/service": "3.38.0",
43
+ "@platformatic/sql-graphql": "3.38.0",
44
+ "@platformatic/sql-mapper": "3.38.0",
45
+ "@platformatic/wattpm-pprof-capture": "3.38.0"
46
46
  },
47
47
  "dependencies": {
48
48
  "@fastify/accepts": "^5.0.0",
@@ -69,14 +69,14 @@
69
69
  "sonic-boom": "^4.2.0",
70
70
  "systeminformation": "^5.27.11",
71
71
  "undici": "^7.0.0",
72
- "undici-thread-interceptor": "^1.3.0",
72
+ "undici-thread-interceptor": "^1.3.1",
73
73
  "ws": "^8.16.0",
74
- "@platformatic/basic": "3.37.0",
75
- "@platformatic/foundation": "3.37.0",
76
- "@platformatic/generators": "3.37.0",
77
- "@platformatic/itc": "3.37.0",
78
- "@platformatic/telemetry": "3.37.0",
79
- "@platformatic/metrics": "3.37.0"
74
+ "@platformatic/foundation": "3.38.0",
75
+ "@platformatic/basic": "3.38.0",
76
+ "@platformatic/generators": "3.38.0",
77
+ "@platformatic/itc": "3.38.0",
78
+ "@platformatic/telemetry": "3.38.0",
79
+ "@platformatic/metrics": "3.38.0"
80
80
  },
81
81
  "engines": {
82
82
  "node": ">=22.19.0"
package/schema.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "$id": "https://schemas.platformatic.dev/@platformatic/runtime/3.37.0.json",
2
+ "$id": "https://schemas.platformatic.dev/@platformatic/runtime/3.38.0.json",
3
3
  "$schema": "http://json-schema.org/draft-07/schema#",
4
4
  "title": "Platformatic Runtime Config",
5
5
  "type": "object",