@platformatic/runtime 2.0.0-alpha.7 → 2.0.0-alpha.8

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/config.d.ts CHANGED
@@ -5,7 +5,7 @@
5
5
  * and run json-schema-to-typescript to regenerate this file.
6
6
  */
7
7
 
8
- export type HttpsSchemasPlatformaticDevPlatformaticRuntime200Alpha7Json = {
8
+ export type HttpsSchemasPlatformaticDevPlatformaticRuntime200Alpha8Json = {
9
9
  [k: string]: unknown;
10
10
  } & {
11
11
  $schema?: string;
@@ -9,7 +9,7 @@ const { platformaticRuntime } = require('./config')
9
9
  const { buildRuntime } = require('./start')
10
10
  const { loadConfig } = require('./utils')
11
11
 
12
- async function buildServerRuntime (options = {}) {
12
+ async function buildServerRuntime (options = {}, args = undefined) {
13
13
  const { serviceMap } = options
14
14
 
15
15
  if (!options.configManager) {
@@ -18,7 +18,7 @@ async function buildServerRuntime (options = {}) {
18
18
  // Instantiate a new config manager from the current options.
19
19
  const cm = new ConfigManager({
20
20
  ...platformaticRuntime.configManagerConfig,
21
- source: options,
21
+ source: options
22
22
  })
23
23
  await cm.parseAndValidate()
24
24
 
@@ -31,10 +31,14 @@ async function buildServerRuntime (options = {}) {
31
31
  }
32
32
  }
33
33
 
34
+ if (args) {
35
+ options.configManager.args = args
36
+ }
37
+
34
38
  return buildRuntime(options.configManager, options.env)
35
39
  }
36
40
 
37
- async function buildServer (options) {
41
+ async function buildServer (options, args) {
38
42
  if (typeof options === 'string') {
39
43
  const config = await loadConfig({}, ['-c', options])
40
44
  options = config.configManager.current
@@ -47,7 +51,7 @@ async function buildServer (options) {
47
51
  delete options.app
48
52
 
49
53
  if (app === platformaticRuntime || !app) {
50
- return buildServerRuntime(options)
54
+ return buildServerRuntime(options, args)
51
55
  }
52
56
 
53
57
  if (app.buildServer) {
package/lib/runtime.js CHANGED
@@ -9,7 +9,10 @@ const { setTimeout: sleep } = require('node:timers/promises')
9
9
  const { Worker } = require('node:worker_threads')
10
10
 
11
11
  const { ITC } = require('@platformatic/itc')
12
- const { Unpromise } = require('@watchable/unpromise')
12
+ const {
13
+ errors: { ensureLoggableError },
14
+ executeWithTimeout
15
+ } = require('@platformatic/utils')
13
16
  const ts = require('tail-file-stream')
14
17
  const { createThreadInterceptor } = require('undici-thread-interceptor')
15
18
 
@@ -64,7 +67,7 @@ class Runtime extends EventEmitter {
64
67
  this.#servicesIds = []
65
68
  this.#url = undefined
66
69
  // Note: nothing hits the main thread so there is no reason to set the globalDispatcher here
67
- this.#interceptor = createThreadInterceptor({ domain: '.plt.local' })
70
+ this.#interceptor = createThreadInterceptor({ domain: '.plt.local', timeout: true })
68
71
  this.#status = undefined
69
72
  this.#startedServices = new Map()
70
73
  this.#restartPromises = new Map()
@@ -148,6 +151,7 @@ class Runtime extends EventEmitter {
148
151
  this.startCollectingMetrics()
149
152
  }
150
153
 
154
+ this.logger.info(`Platformatic is now listening at ${this.#url}`)
151
155
  return this.#url
152
156
  }
153
157
 
@@ -172,6 +176,7 @@ class Runtime extends EventEmitter {
172
176
 
173
177
  this.emit('restarted')
174
178
 
179
+ this.logger.info(`Platformatic is now listening at ${this.#url}`)
175
180
  return this.#url
176
181
  }
177
182
 
@@ -236,7 +241,7 @@ class Runtime extends EventEmitter {
236
241
  // TODO: handle port allocation error here
237
242
  if (error.code === 'EADDRINUSE') throw error
238
243
 
239
- this.logger.error({ error }, `Failed to start service "${id}".`)
244
+ this.logger.error({ error: ensureLoggableError(error) }, `Failed to start service "${id}".`)
240
245
 
241
246
  const config = this.#configManager.current
242
247
  const restartOnError = config.restartOnError
@@ -278,13 +283,18 @@ class Runtime extends EventEmitter {
278
283
 
279
284
  // Always send the stop message, it will shut down workers that only had ITC and interceptors setup
280
285
  try {
281
- await Unpromise.race([sendViaITC(service, 'stop'), sleep(10000, 'timeout', { ref: false })])
286
+ await executeWithTimeout(sendViaITC(service, 'stop'), 10000)
282
287
  } catch (error) {
283
- this.logger?.info(`Failed to stop service "${id}". Killing a worker thread.`, error)
288
+ this.logger?.info(
289
+ { error: ensureLoggableError(error) },
290
+ `Failed to stop service "${id}". Killing a worker thread.`
291
+ )
292
+ } finally {
293
+ service[kITC].close()
284
294
  }
285
295
 
286
296
  // Wait for the worker thread to finish, we're going to create a new one if the service is ever restarted
287
- const res = await Unpromise.race([once(service, 'exit'), sleep(10000, 'timeout', { ref: false })])
297
+ const res = await executeWithTimeout(once(service, 'exit'), 10000)
288
298
 
289
299
  // If the worker didn't exit in time, kill it
290
300
  if (res === 'timeout') {
@@ -292,6 +302,25 @@ class Runtime extends EventEmitter {
292
302
  }
293
303
  }
294
304
 
305
+ async buildService (id) {
306
+ const service = this.#services.get(id)
307
+
308
+ if (!service) {
309
+ throw new errors.ServiceNotFoundError(id, Array.from(this.#services.keys()).join(', '))
310
+ }
311
+
312
+ try {
313
+ return await sendViaITC(service, 'build')
314
+ } catch (e) {
315
+ // The service exports no meta, return an empty object
316
+ if (e.code === 'PLT_ITC_HANDLER_NOT_FOUND') {
317
+ return {}
318
+ }
319
+
320
+ throw e
321
+ }
322
+ }
323
+
295
324
  async inject (id, injectParams) {
296
325
  const service = await this.#getServiceById(id, true)
297
326
  return sendViaITC(service, 'inject', injectParams)
@@ -577,9 +606,7 @@ class Runtime extends EventEmitter {
577
606
  let p99Value = 0
578
607
 
579
608
  const metricName = 'http_request_all_summary_seconds'
580
- const httpLatencyMetrics = metrics.filter(
581
- metric => metric.name === metricName
582
- )
609
+ const httpLatencyMetrics = metrics.filter(metric => metric.name === metricName)
583
610
 
584
611
  if (httpLatencyMetrics) {
585
612
  const entrypointMetrics = httpLatencyMetrics.find(
@@ -635,6 +662,25 @@ class Runtime extends EventEmitter {
635
662
  }
636
663
  }
637
664
 
665
+ async getServiceMeta (id) {
666
+ const service = this.#services.get(id)
667
+
668
+ if (!service) {
669
+ throw new errors.ServiceNotFoundError(id, Array.from(this.#services.keys()).join(', '))
670
+ }
671
+
672
+ try {
673
+ return await sendViaITC(service, 'getServiceMeta')
674
+ } catch (e) {
675
+ // The service exports no meta, return an empty object
676
+ if (e.code === 'PLT_ITC_HANDLER_NOT_FOUND') {
677
+ return {}
678
+ }
679
+
680
+ throw e
681
+ }
682
+ }
683
+
638
684
  async getLogIds (runtimePID) {
639
685
  runtimePID = runtimePID ?? process.pid
640
686
 
@@ -695,7 +741,10 @@ class Runtime extends EventEmitter {
695
741
  const service = new Worker(kWorkerFile, {
696
742
  workerData: {
697
743
  config,
698
- serviceConfig,
744
+ serviceConfig: {
745
+ ...serviceConfig,
746
+ isProduction: this.#configManager.args?.production ?? false
747
+ },
699
748
  dirname: this.#configManager.dirname,
700
749
  runtimeLogsDir: this.#runtimeLogsDir,
701
750
  loggingPort
@@ -722,6 +771,7 @@ class Runtime extends EventEmitter {
722
771
  const started = this.#startedServices.get(id)
723
772
  this.#services.delete(id)
724
773
  loggerDestination.close()
774
+ service[kITC].close()
725
775
  loggingPort.close()
726
776
 
727
777
  if (this.#status === 'stopping') return
@@ -735,7 +785,7 @@ class Runtime extends EventEmitter {
735
785
  if (restartOnError > 0) {
736
786
  this.logger.warn(`Restarting a service "${id}" in ${restartOnError}ms...`)
737
787
  this.#restartCrashedService(id).catch(err => {
738
- this.logger.error({ err }, `Failed to restart service "${id}".`)
788
+ this.logger.error({ err: ensureLoggableError(err) }, `Failed to restart service "${id}".`)
739
789
  })
740
790
  } else {
741
791
  this.logger.warn(`The "${id}" service is no longer available.`)
@@ -749,6 +799,7 @@ class Runtime extends EventEmitter {
749
799
 
750
800
  // Setup ITC
751
801
  service[kITC] = new ITC({
802
+ name: id + '-runtime',
752
803
  port: service,
753
804
  handlers: {
754
805
  getServiceMeta: this.getServiceMeta.bind(this)
@@ -856,25 +907,6 @@ class Runtime extends EventEmitter {
856
907
  return service
857
908
  }
858
909
 
859
- async getServiceMeta (id) {
860
- const service = this.#services.get(id)
861
-
862
- if (!service) {
863
- throw new errors.ServiceNotFoundError(id, Array.from(this.#services.keys()).join(', '))
864
- }
865
-
866
- try {
867
- return await service[kITC].send('getServiceMeta')
868
- } catch (e) {
869
- // The service exports no meta, return an empty object
870
- if (e.code === 'PLT_ITC_HANDLER_NOT_FOUND') {
871
- return {}
872
- }
873
-
874
- throw e
875
- }
876
- }
877
-
878
910
  async #getRuntimePackageJson () {
879
911
  const runtimeDir = this.#configManager.dirname
880
912
  const packageJsonPath = join(runtimeDir, 'package.json')
@@ -903,7 +935,7 @@ class Runtime extends EventEmitter {
903
935
  try {
904
936
  await access(this.#runtimeTmpDir)
905
937
  } catch (err) {
906
- this.logger.error({ err }, 'Cannot access temporary folder.')
938
+ this.logger.error({ err: ensureLoggableError(err) }, 'Cannot access temporary folder.')
907
939
  return []
908
940
  }
909
941
 
package/lib/schema.js CHANGED
@@ -2,7 +2,9 @@
2
2
  'use strict'
3
3
 
4
4
  const telemetry = require('@platformatic/telemetry').schema
5
- const { schemas: { server } } = require('@platformatic/utils')
5
+ const {
6
+ schemaComponents: { server }
7
+ } = require('@platformatic/utils')
6
8
 
7
9
  const pkg = require('../package.json')
8
10
  const platformaticRuntimeSchema = {
@@ -11,11 +13,11 @@ const platformaticRuntimeSchema = {
11
13
  type: 'object',
12
14
  properties: {
13
15
  $schema: {
14
- type: 'string',
16
+ type: 'string'
15
17
  },
16
18
  preload: {
17
19
  type: 'string',
18
- resolvePath: true,
20
+ resolvePath: true
19
21
  },
20
22
  autoload: {
21
23
  type: 'object',
@@ -24,14 +26,14 @@ const platformaticRuntimeSchema = {
24
26
  properties: {
25
27
  path: {
26
28
  type: 'string',
27
- resolvePath: true,
29
+ resolvePath: true
28
30
  },
29
31
  exclude: {
30
32
  type: 'array',
31
33
  default: [],
32
34
  items: {
33
- type: 'string',
34
- },
35
+ type: 'string'
36
+ }
35
37
  },
36
38
  mappings: {
37
39
  type: 'object',
@@ -41,89 +43,92 @@ const platformaticRuntimeSchema = {
41
43
  required: ['id'],
42
44
  properties: {
43
45
  id: {
44
- type: 'string',
46
+ type: 'string'
45
47
  },
46
48
  config: {
47
- type: 'string',
49
+ type: 'string'
48
50
  },
49
51
  useHttp: {
50
- type: 'boolean',
51
- },
52
- },
53
- },
54
- },
55
- },
52
+ type: 'boolean'
53
+ }
54
+ }
55
+ }
56
+ }
57
+ }
56
58
  },
57
59
  telemetry,
58
60
  server,
59
61
  entrypoint: {
60
- type: 'string',
62
+ type: 'string'
61
63
  },
62
64
  watch: {
63
65
  anyOf: [
64
66
  {
65
- type: 'boolean',
67
+ type: 'boolean'
66
68
  },
67
69
  {
68
- type: 'string',
69
- },
70
- ],
70
+ type: 'string'
71
+ }
72
+ ]
71
73
  },
72
74
  inspectorOptions: {
73
75
  type: 'object',
74
76
  properties: {
75
77
  host: {
76
- type: 'string',
78
+ type: 'string'
77
79
  },
78
80
  port: {
79
- type: 'number',
81
+ type: 'number'
80
82
  },
81
83
  breakFirstLine: {
82
- type: 'boolean',
84
+ type: 'boolean'
83
85
  },
84
86
  watchDisabled: {
85
- type: 'boolean',
86
- },
87
- },
87
+ type: 'boolean'
88
+ }
89
+ }
88
90
  },
89
91
  undici: {
90
92
  type: 'object',
91
93
  properties: {
92
94
  agentOptions: {
93
95
  type: 'object',
94
- additionalProperties: true,
96
+ additionalProperties: true
95
97
  },
96
98
  interceptors: {
97
- anyOf: [{
98
- type: 'array',
99
- items: {
100
- $ref: '#/$defs/undiciInterceptor',
99
+ anyOf: [
100
+ {
101
+ type: 'array',
102
+ items: {
103
+ $ref: '#/$defs/undiciInterceptor'
104
+ }
101
105
  },
102
- }, {
103
- type: 'object',
104
- properties: {
105
- Client: {
106
- type: 'array',
107
- items: {
108
- $ref: '#/$defs/undiciInterceptor',
109
- },
110
- },
111
- Pool: {
112
- type: 'array',
113
- items: {
114
- $ref: '#/$defs/undiciInterceptor',
106
+ {
107
+ type: 'object',
108
+ properties: {
109
+ Client: {
110
+ type: 'array',
111
+ items: {
112
+ $ref: '#/$defs/undiciInterceptor'
113
+ }
115
114
  },
116
- },
117
- Agent: {
118
- type: 'array',
119
- items: {
120
- $ref: '#/$defs/undiciInterceptor',
115
+ Pool: {
116
+ type: 'array',
117
+ items: {
118
+ $ref: '#/$defs/undiciInterceptor'
119
+ }
121
120
  },
122
- },
123
- },
124
- }],
125
- },
126
- },
121
+ Agent: {
122
+ type: 'array',
123
+ items: {
124
+ $ref: '#/$defs/undiciInterceptor'
125
+ }
126
+ }
127
+ }
128
+ }
129
+ ]
130
+ }
131
+ }
127
132
  },
128
133
  managementApi: {
129
134
  anyOf: [
@@ -136,14 +141,14 @@ const platformaticRuntimeSchema = {
136
141
  maxSize: {
137
142
  type: 'number',
138
143
  minimum: 5,
139
- default: 200,
140
- },
141
- },
144
+ default: 200
145
+ }
146
+ }
142
147
  },
143
- additionalProperties: false,
144
- },
148
+ additionalProperties: false
149
+ }
145
150
  ],
146
- default: true,
151
+ default: true
147
152
  },
148
153
  metrics: {
149
154
  anyOf: [
@@ -152,10 +157,7 @@ const platformaticRuntimeSchema = {
152
157
  type: 'object',
153
158
  properties: {
154
159
  port: {
155
- anyOf: [
156
- { type: 'integer' },
157
- { type: 'string' },
158
- ],
160
+ anyOf: [{ type: 'integer' }, { type: 'string' }]
159
161
  },
160
162
  hostname: { type: 'string' },
161
163
  endpoint: { type: 'string' },
@@ -163,19 +165,19 @@ const platformaticRuntimeSchema = {
163
165
  type: 'object',
164
166
  properties: {
165
167
  username: { type: 'string' },
166
- password: { type: 'string' },
168
+ password: { type: 'string' }
167
169
  },
168
170
  additionalProperties: false,
169
- required: ['username', 'password'],
171
+ required: ['username', 'password']
170
172
  },
171
173
  labels: {
172
174
  type: 'object',
173
- additionalProperties: { type: 'string' },
174
- },
175
+ additionalProperties: { type: 'string' }
176
+ }
175
177
  },
176
- additionalProperties: false,
177
- },
178
- ],
178
+ additionalProperties: false
179
+ }
180
+ ]
179
181
  },
180
182
  restartOnError: {
181
183
  default: true,
@@ -183,59 +185,53 @@ const platformaticRuntimeSchema = {
183
185
  { type: 'boolean' },
184
186
  {
185
187
  type: 'number',
186
- minimum: 100,
187
- },
188
- ],
188
+ minimum: 100
189
+ }
190
+ ]
189
191
  },
190
192
  services: {
191
193
  type: 'array',
192
194
  items: {
193
195
  type: 'object',
194
- anyOf: [
195
- { required: ['id', 'path'] },
196
- { required: ['id', 'url'] },
197
- ],
196
+ anyOf: [{ required: ['id', 'path'] }, { required: ['id', 'url'] }],
198
197
  properties: {
199
198
  id: {
200
- type: 'string',
199
+ type: 'string'
201
200
  },
202
201
  path: {
203
202
  type: 'string',
204
- resolvePath: true,
203
+ resolvePath: true
205
204
  },
206
205
  config: {
207
- type: 'string',
206
+ type: 'string'
208
207
  },
209
208
  url: {
210
- type: 'string',
209
+ type: 'string'
211
210
  },
212
211
  useHttp: {
213
- type: 'boolean',
214
- },
215
- },
216
- },
217
- },
212
+ type: 'boolean'
213
+ }
214
+ }
215
+ }
216
+ }
218
217
  },
219
- anyOf: [
220
- { required: ['autoload', 'entrypoint'] },
221
- { required: ['services', 'entrypoint'] },
222
- ],
218
+ anyOf: [{ required: ['autoload', 'entrypoint'] }, { required: ['services', 'entrypoint'] }],
223
219
  additionalProperties: false,
224
220
  $defs: {
225
221
  undiciInterceptor: {
226
222
  type: 'object',
227
223
  properties: {
228
224
  module: {
229
- type: 'string',
225
+ type: 'string'
230
226
  },
231
227
  options: {
232
228
  type: 'object',
233
- additionalProperties: true,
234
- },
229
+ additionalProperties: true
230
+ }
235
231
  },
236
- required: ['module', 'options'],
237
- },
238
- },
232
+ required: ['module', 'options']
233
+ }
234
+ }
239
235
  }
240
236
 
241
237
  module.exports.schema = platformaticRuntimeSchema
package/lib/start.js CHANGED
@@ -5,6 +5,9 @@ const { writeFile } = require('node:fs/promises')
5
5
  const { join, resolve, dirname } = require('node:path')
6
6
 
7
7
  const { printConfigValidationErrors } = require('@platformatic/config')
8
+ const {
9
+ errors: { ensureLoggableError }
10
+ } = require('@platformatic/utils')
8
11
  const closeWithGrace = require('close-with-grace')
9
12
  const pino = require('pino')
10
13
  const pretty = require('pino-pretty')
@@ -38,7 +41,7 @@ async function buildRuntime (configManager, env) {
38
41
  try {
39
42
  await runtime.restart()
40
43
  } catch (err) {
41
- runtime.logger.error({ err }, 'Failed to restart services.')
44
+ runtime.logger.error({ err: ensureLoggableError(err) }, 'Failed to restart services.')
42
45
  }
43
46
  })
44
47
 
@@ -96,7 +99,7 @@ async function setupAndStartRuntime (config) {
96
99
  const logger = pino(
97
100
  pretty({
98
101
  translateTime: 'SYS:HH:MM:ss',
99
- ignore: 'hostname,pid',
102
+ ignore: 'hostname,pid'
100
103
  })
101
104
  )
102
105
  logger.warn(`Port: ${originalPort} is already in use!`)
@@ -107,7 +110,15 @@ async function setupAndStartRuntime (config) {
107
110
 
108
111
  async function startCommand (args) {
109
112
  try {
110
- const config = await loadConfig({}, args)
113
+ const config = await loadConfig(
114
+ {
115
+ alias: {
116
+ p: 'production'
117
+ },
118
+ boolean: ['p', 'production']
119
+ },
120
+ args
121
+ )
111
122
 
112
123
  const startResult = await setupAndStartRuntime(config)
113
124
 
@@ -130,16 +141,16 @@ async function startCommand (args) {
130
141
  hostname: '127.0.0.1',
131
142
  port: 3042,
132
143
  logger: {
133
- level: 'info',
134
- },
144
+ level: 'info'
145
+ }
135
146
  },
136
147
  plugins: {
137
- paths: [args[0]],
148
+ paths: [args[0]]
138
149
  },
139
150
  service: {
140
- openapi: true,
151
+ openapi: true
141
152
  },
142
- watch: true,
153
+ watch: true
143
154
  }
144
155
  const toWrite = join(dirname(resolve(args[0])), 'platformatic.service.json')
145
156
  console.log(`No config file found, creating ${join(dirname(args[0]), 'platformatic.service.json')}`)
package/lib/worker/app.js CHANGED
@@ -35,12 +35,12 @@ class PlatformaticApp extends EventEmitter {
35
35
  serviceId: this.appConfig.id,
36
36
  directory: this.appConfig.path,
37
37
  isEntrypoint: this.appConfig.entrypoint,
38
- isProduction: false,
38
+ isProduction: this.appConfig.isProduction,
39
39
  telemetryConfig,
40
40
  metricsConfig,
41
41
  serverConfig,
42
42
  hasManagementApi: !!hasManagementApi,
43
- localServiceEnvVars: this.appConfig.localServiceEnvVars,
43
+ localServiceEnvVars: this.appConfig.localServiceEnvVars
44
44
  }
45
45
  }
46
46
 
@@ -71,7 +71,7 @@ class PlatformaticApp extends EventEmitter {
71
71
  appConfig.path,
72
72
  {
73
73
  onMissingEnv: this.#fetchServiceUrl,
74
- context: appConfig,
74
+ context: appConfig
75
75
  },
76
76
  true
77
77
  )
@@ -81,7 +81,7 @@ class PlatformaticApp extends EventEmitter {
81
81
  ['-c', appConfig.config],
82
82
  {
83
83
  onMissingEnv: this.#fetchServiceUrl,
84
- context: appConfig,
84
+ context: appConfig
85
85
  },
86
86
  true
87
87
  )
@@ -89,10 +89,14 @@ class PlatformaticApp extends EventEmitter {
89
89
 
90
90
  const app = loadedConfig.app
91
91
 
92
+ if (appConfig.isProduction && !process.env.NODE_ENV) {
93
+ process.env.NODE_ENV = 'production'
94
+ }
95
+
92
96
  const stackable = await app.buildStackable({
93
97
  onMissingEnv: this.#fetchServiceUrl,
94
98
  config: this.appConfig.config,
95
- context: this.#context,
99
+ context: this.#context
96
100
  })
97
101
  this.stackable = this.#wrapStackable(stackable)
98
102
 
@@ -203,7 +207,7 @@ class PlatformaticApp extends EventEmitter {
203
207
  path: watch.path,
204
208
  /* c8 ignore next 2 */
205
209
  allowToWatch: watch?.allow,
206
- watchIgnore: watch?.ignore || [],
210
+ watchIgnore: watch?.ignore || []
207
211
  })
208
212
 
209
213
  fileWatcher.on('update', this.#debouncedRestart)
@@ -246,7 +250,7 @@ class PlatformaticApp extends EventEmitter {
246
250
  if (telemetryId) {
247
251
  opts.headers = {
248
252
  ...opts.headers,
249
- 'x-plt-telemetry-id': telemetryId,
253
+ 'x-plt-telemetry-id': telemetryId
250
254
  }
251
255
  }
252
256
  return dispatch(opts, handler)
@@ -6,6 +6,7 @@ const defaultStackable = {
6
6
  throw new Error('Stackable start not implemented')
7
7
  },
8
8
  stop: () => {},
9
+ build: () => {},
9
10
  getUrl: () => null,
10
11
  updateContext: () => {},
11
12
  getConfig: () => null,
package/lib/worker/itc.js CHANGED
@@ -44,6 +44,7 @@ async function sendViaITC (worker, name, message) {
44
44
 
45
45
  function setupITC (app, service, dispatcher) {
46
46
  const itc = new ITC({
47
+ name: app.appConfig.id + '-worker',
47
48
  port: parentPort,
48
49
  handlers: {
49
50
  async start () {
@@ -82,6 +83,10 @@ function setupITC (app, service, dispatcher) {
82
83
  itc.close()
83
84
  },
84
85
 
86
+ async build () {
87
+ return app.stackable.build()
88
+ },
89
+
85
90
  getStatus () {
86
91
  return app.getStatus()
87
92
  },
@@ -2,11 +2,9 @@
2
2
 
3
3
  const { createRequire } = require('node:module')
4
4
  const { join } = require('node:path')
5
- const { setTimeout: sleep } = require('node:timers/promises')
6
5
  const { parentPort, workerData, threadId } = require('node:worker_threads')
7
6
  const { pathToFileURL } = require('node:url')
8
7
 
9
- const { Unpromise } = require('@watchable/unpromise')
10
8
  const pino = require('pino')
11
9
  const { fetch, setGlobalDispatcher, Agent } = require('undici')
12
10
  const { wire } = require('undici-thread-interceptor')
@@ -14,7 +12,7 @@ const { wire } = require('undici-thread-interceptor')
14
12
  const { PlatformaticApp } = require('./app')
15
13
  const { setupITC } = require('./itc')
16
14
  const loadInterceptors = require('./interceptors')
17
- const { MessagePortWritable, createPinoWritable } = require('@platformatic/utils')
15
+ const { MessagePortWritable, createPinoWritable, executeWithTimeout, errors } = require('@platformatic/utils')
18
16
  const { kId, kITC } = require('./symbols')
19
17
 
20
18
  process.on('uncaughtException', handleUnhandled.bind(null, 'uncaught exception'))
@@ -25,12 +23,15 @@ globalThis[kId] = threadId
25
23
 
26
24
  let app
27
25
  const config = workerData.config
28
- const logger = createLogger()
26
+ globalThis.platformatic = Object.assign(globalThis.platformatic ?? {}, { logger: createLogger() })
29
27
 
30
28
  function handleUnhandled (type, err) {
31
- logger.error({ err }, `application ${type}`)
29
+ globalThis.platformatic.logger.error(
30
+ { err: errors.ensureLoggableError(err) },
31
+ `Service ${workerData.serviceConfig.id} threw an ${type}.`
32
+ )
32
33
 
33
- Unpromise.race([app?.stop(), sleep(1000, 'timeout', { ref: false })])
34
+ executeWithTimeout(app?.stop(), 1000)
34
35
  .catch()
35
36
  .finally(() => {
36
37
  process.exit(1)
@@ -73,13 +74,13 @@ async function main () {
73
74
 
74
75
  const globalDispatcher = new Agent({
75
76
  ...config.undici,
76
- interceptors,
77
+ interceptors
77
78
  }).compose(composedInterceptors)
78
79
 
79
80
  setGlobalDispatcher(globalDispatcher)
80
81
 
81
82
  // Setup mesh networker
82
- const threadDispatcher = wire({ port: parentPort, useNetwork: service.useHttp })
83
+ const threadDispatcher = wire({ port: parentPort, useNetwork: service.useHttp, timeout: true })
83
84
 
84
85
  // If the service is an entrypoint and runtime server config is defined, use it.
85
86
  let serverConfig = null
@@ -89,7 +90,7 @@ async function main () {
89
90
  serverConfig = {
90
91
  port: 0,
91
92
  hostname: '127.0.0.1',
92
- keepAliveTimeout: 5000,
93
+ keepAliveTimeout: 5000
93
94
  }
94
95
  }
95
96
 
@@ -97,7 +98,7 @@ async function main () {
97
98
  if (telemetryConfig) {
98
99
  telemetryConfig = {
99
100
  ...telemetryConfig,
100
- serviceName: `${telemetryConfig.serviceName}-${service.id}`,
101
+ serviceName: `${telemetryConfig.serviceName}-${service.id}`
101
102
  }
102
103
  }
103
104
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@platformatic/runtime",
3
- "version": "2.0.0-alpha.7",
3
+ "version": "2.0.0-alpha.8",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -34,11 +34,11 @@
34
34
  "typescript": "^5.5.4",
35
35
  "undici-oidc-interceptor": "^0.5.0",
36
36
  "why-is-node-running": "^2.2.2",
37
- "@platformatic/composer": "2.0.0-alpha.7",
38
- "@platformatic/db": "2.0.0-alpha.7",
39
- "@platformatic/service": "2.0.0-alpha.7",
40
- "@platformatic/sql-graphql": "2.0.0-alpha.7",
41
- "@platformatic/sql-mapper": "2.0.0-alpha.7"
37
+ "@platformatic/composer": "2.0.0-alpha.8",
38
+ "@platformatic/service": "2.0.0-alpha.8",
39
+ "@platformatic/sql-graphql": "2.0.0-alpha.8",
40
+ "@platformatic/sql-mapper": "2.0.0-alpha.8",
41
+ "@platformatic/db": "2.0.0-alpha.8"
42
42
  },
43
43
  "dependencies": {
44
44
  "@fastify/error": "^3.4.1",
@@ -67,15 +67,15 @@
67
67
  "semgrator": "^0.3.0",
68
68
  "tail-file-stream": "^0.2.0",
69
69
  "undici": "^6.9.0",
70
- "undici-thread-interceptor": "^0.5.1",
70
+ "undici-thread-interceptor": "^0.6.1",
71
71
  "ws": "^8.16.0",
72
- "@platformatic/basic": "2.0.0-alpha.7",
73
- "@platformatic/config": "2.0.0-alpha.7",
74
- "@platformatic/generators": "2.0.0-alpha.7",
75
- "@platformatic/itc": "2.0.0-alpha.7",
76
- "@platformatic/telemetry": "2.0.0-alpha.7",
77
- "@platformatic/ts-compiler": "2.0.0-alpha.7",
78
- "@platformatic/utils": "2.0.0-alpha.7"
72
+ "@platformatic/basic": "2.0.0-alpha.8",
73
+ "@platformatic/config": "2.0.0-alpha.8",
74
+ "@platformatic/generators": "2.0.0-alpha.8",
75
+ "@platformatic/itc": "2.0.0-alpha.8",
76
+ "@platformatic/telemetry": "2.0.0-alpha.8",
77
+ "@platformatic/ts-compiler": "2.0.0-alpha.8",
78
+ "@platformatic/utils": "2.0.0-alpha.8"
79
79
  },
80
80
  "scripts": {
81
81
  "test": "npm run lint && borp --concurrency=1 --timeout=180000 && tsd",
package/schema.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "$id": "https://schemas.platformatic.dev/@platformatic/runtime/2.0.0-alpha.7.json",
2
+ "$id": "https://schemas.platformatic.dev/@platformatic/runtime/2.0.0-alpha.8.json",
3
3
  "$schema": "http://json-schema.org/draft-07/schema#",
4
4
  "type": "object",
5
5
  "properties": {