@platformatic/runtime 3.5.0 → 3.6.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/config.d.ts CHANGED
@@ -48,6 +48,7 @@ export type PlatformaticRuntimeConfig = {
48
48
  [k: string]: unknown;
49
49
  }[];
50
50
  workers?: number | string;
51
+ workersRestartDelay?: number | string;
51
52
  logger?: {
52
53
  level: (
53
54
  | ("fatal" | "error" | "warn" | "info" | "debug" | "trace" | "silent")
package/index.js CHANGED
@@ -36,9 +36,13 @@ function handleSignal (runtime, config) {
36
36
  }
37
37
  }
38
38
 
39
+ function onTimeout (timeout) {
40
+ runtime.logger.error(`Could not close the runtime in ${timeout} ms, aborting the process with exit code 1.`)
41
+ }
42
+
39
43
  process.on('newListener', filterCloseWithGraceSIGUSR2)
40
44
 
41
- const cwg = closeWithGrace({ delay: config.gracefulShutdown?.runtime ?? 10000 }, async event => {
45
+ const cwg = closeWithGrace({ delay: config.gracefulShutdown?.runtime ?? 10000, onTimeout }, async event => {
42
46
  if (event.err instanceof Error) {
43
47
  console.error(event.err)
44
48
  }
package/lib/errors.js CHANGED
@@ -105,7 +105,7 @@ export const CannotMapSpecifierToAbsolutePathError = createError(
105
105
  )
106
106
  export const NodeInspectorFlagsNotSupportedError = createError(
107
107
  `${ERROR_PREFIX}_NODE_INSPECTOR_FLAGS_NOT_SUPPORTED`,
108
- "The Node.js inspector flags are not supported. Please use 'platformatic start --inspect' instead."
108
+ "The Node.js inspector flags are not supported. Please use 'wattpm start --inspect' instead."
109
109
  )
110
110
  export const FailedToUnlinkManagementApiSocket = createError(
111
111
  `${ERROR_PREFIX}_FAILED_TO_UNLINK_MANAGEMENT_API_SOCKET`,
package/lib/generator.js CHANGED
@@ -103,9 +103,9 @@ export class RuntimeGenerator extends BaseGenerator {
103
103
  const template = {
104
104
  name: `${this.runtimeName}`,
105
105
  scripts: {
106
- dev: this.config.devCommand,
107
- build: this.config.buildCommand,
108
- start: this.config.startCommand ?? 'platformatic start'
106
+ dev: this.config.devCommand ?? 'wattpm dev',
107
+ build: this.config.buildCommand ?? 'wattpm build',
108
+ start: this.config.startCommand ?? 'wattpm start'
109
109
  },
110
110
  devDependencies: {
111
111
  fastify: `^${this.fastifyVersion}`
@@ -594,7 +594,7 @@ export class WrappedGenerator extends BaseGenerator {
594
594
  scripts ??= {}
595
595
  scripts.dev ??= this.config.devCommand
596
596
  scripts.build ??= this.config.buildCommand
597
- scripts.start ??= this.config.startCommand ?? 'platformatic start'
597
+ scripts.start ??= this.config.startCommand ?? 'wattpm start'
598
598
 
599
599
  this.addFile({
600
600
  path: '',
@@ -36,9 +36,10 @@ export async function managementApiPlugin (app, opts) {
36
36
  await runtime.close()
37
37
  })
38
38
 
39
- app.post('/restart', async () => {
40
- app.log.debug('restart applications')
41
- await runtime.restart()
39
+ app.post('/restart', async request => {
40
+ const applications = request.body?.applications ?? []
41
+ app.log.debug({ applications }, 'restart applications')
42
+ await runtime.restart(applications)
42
43
  })
43
44
 
44
45
  app.get('/applications', async () => {
package/lib/runtime.js CHANGED
@@ -337,14 +337,19 @@ export class Runtime extends EventEmitter {
337
337
  this.#updateStatus('stopped')
338
338
  }
339
339
 
340
- async restart () {
341
- this.emit('restarting')
340
+ async restart (applications = []) {
341
+ this.emitAndNotify('restarting')
342
342
 
343
- await this.stop()
344
- this.#meshInterceptor.restart()
345
- await this.start()
343
+ const restartInvocations = []
344
+ for (const application of this.getApplicationsIds()) {
345
+ if (applications.length === 0 || applications.includes(application)) {
346
+ restartInvocations.push([application])
347
+ }
348
+ }
349
+
350
+ await executeInParallel(this.restartApplication.bind(this), restartInvocations, this.#concurrency)
346
351
 
347
- this.emit('restarted')
352
+ this.emitAndNotify('restarted')
348
353
 
349
354
  return this.#url
350
355
  }
@@ -362,6 +367,10 @@ export class Runtime extends EventEmitter {
362
367
  await this.#prometheusServer.close()
363
368
  }
364
369
 
370
+ if (this.#sharedHttpCache?.close) {
371
+ await this.#sharedHttpCache.close()
372
+ }
373
+
365
374
  if (this.logger) {
366
375
  this.#loggerDestination?.end()
367
376
 
@@ -369,10 +378,6 @@ export class Runtime extends EventEmitter {
369
378
  this.#loggerDestination = null
370
379
  }
371
380
 
372
- if (this.#sharedHttpCache?.close) {
373
- await this.#sharedHttpCache.close()
374
- }
375
-
376
381
  this.#updateStatus('closed')
377
382
  }
378
383
 
@@ -432,13 +437,13 @@ export class Runtime extends EventEmitter {
432
437
  }
433
438
  }
434
439
 
435
- emit (event, payload) {
440
+ emitAndNotify (event, ...payload) {
436
441
  for (const worker of this.#workers.values()) {
437
442
  worker[kITC].notify('runtime:event', { event, payload })
438
443
  }
439
444
 
440
445
  this.logger.trace({ event, payload }, 'Runtime event')
441
- return super.emit(event, payload)
446
+ return this.emit(event, ...payload)
442
447
  }
443
448
 
444
449
  async sendCommandToApplication (id, name, message) {
@@ -473,13 +478,13 @@ export class Runtime extends EventEmitter {
473
478
 
474
479
  const workersCount = await this.#workers.getCount(applicationConfig.id)
475
480
 
476
- this.emit('application:starting', id)
481
+ this.emitAndNotify('application:starting', id)
477
482
 
478
483
  for (let i = 0; i < workersCount; i++) {
479
484
  await this.#startWorker(config, applicationConfig, workersCount, id, i, silent)
480
485
  }
481
486
 
482
- this.emit('application:started', id)
487
+ this.emitAndNotify('application:started', id)
483
488
  }
484
489
 
485
490
  async stopApplication (id, silent = false, dependents = []) {
@@ -492,7 +497,7 @@ export class Runtime extends EventEmitter {
492
497
 
493
498
  const workersCount = await this.#workers.getCount(applicationConfig.id)
494
499
 
495
- this.emit('application:stopping', id)
500
+ this.emitAndNotify('application:stopping', id)
496
501
 
497
502
  if (typeof workersCount === 'number') {
498
503
  const stopInvocations = []
@@ -503,16 +508,37 @@ export class Runtime extends EventEmitter {
503
508
  await executeInParallel(this.#stopWorker.bind(this), stopInvocations, this.#concurrency)
504
509
  }
505
510
 
506
- this.emit('application:stopped', id)
511
+ this.emitAndNotify('application:stopped', id)
512
+ }
513
+
514
+ async restartApplication (id) {
515
+ const config = this.#config
516
+ const applicationConfig = this.#config.applications.find(s => s.id === id)
517
+ const workersCount = await this.#workers.getCount(id)
518
+
519
+ this.emitAndNotify('application:restarting', id)
520
+
521
+ for (let i = 0; i < workersCount; i++) {
522
+ const label = `${id}:${i}`
523
+ const worker = this.#workers.get(label)
524
+
525
+ if (i > 0 && config.workersRestartDelay > 0) {
526
+ await sleep(config.workersRestartDelay)
527
+ }
528
+
529
+ await this.#replaceWorker(config, applicationConfig, workersCount, id, i, worker, true)
530
+ }
531
+
532
+ this.emitAndNotify('application:restarted', id)
507
533
  }
508
534
 
509
535
  async buildApplication (id) {
510
536
  const application = await this.#getApplicationById(id)
511
537
 
512
- this.emit('application:building', id)
538
+ this.emitAndNotify('application:building', id)
513
539
  try {
514
540
  await sendViaITC(application, 'build')
515
- this.emit('application:built', id)
541
+ this.emitAndNotify('application:built', id)
516
542
  } catch (e) {
517
543
  // The application exports no meta, return an empty object
518
544
  if (e.code === 'PLT_ITC_HANDLER_NOT_FOUND') {
@@ -570,7 +596,7 @@ export class Runtime extends EventEmitter {
570
596
  return
571
597
  }
572
598
 
573
- this.emit('metrics', metrics)
599
+ this.emitAndNotify('metrics', metrics)
574
600
  this.#metrics.push(metrics)
575
601
  if (this.#metrics.length > MAX_METRICS_QUEUE_LENGTH) {
576
602
  this.#metrics.shift()
@@ -1176,7 +1202,7 @@ export class Runtime extends EventEmitter {
1176
1202
 
1177
1203
  #updateStatus (status, args) {
1178
1204
  this.#status = status
1179
- this.emit(status, args)
1205
+ this.emitAndNotify(status, args)
1180
1206
  }
1181
1207
 
1182
1208
  #showUrl () {
@@ -1236,7 +1262,7 @@ export class Runtime extends EventEmitter {
1236
1262
 
1237
1263
  await executeInParallel(this.#setupWorker.bind(this), setupInvocations, this.#concurrency)
1238
1264
 
1239
- this.emit('application:init', id)
1265
+ this.emitAndNotify('application:init', id)
1240
1266
  }
1241
1267
 
1242
1268
  async #setupWorker (config, applicationConfig, workersCount, applicationId, index, enabled = true) {
@@ -1345,7 +1371,7 @@ export class Runtime extends EventEmitter {
1345
1371
 
1346
1372
  const started = worker[kWorkerStatus] === 'started'
1347
1373
  worker[kWorkerStatus] = 'exited'
1348
- this.emit('application:worker:exited', eventPayload)
1374
+ this.emitAndNotify('application:worker:exited', eventPayload)
1349
1375
 
1350
1376
  this.#cleanupWorker(worker)
1351
1377
 
@@ -1356,7 +1382,7 @@ export class Runtime extends EventEmitter {
1356
1382
  // Wait for the next tick so that crashed from the thread are logged first
1357
1383
  setImmediate(() => {
1358
1384
  if (started && (!config.watch || code !== 0)) {
1359
- this.emit('application:worker:error', { ...eventPayload, code })
1385
+ this.emitAndNotify('application:worker:error', { ...eventPayload, code })
1360
1386
  this.#broadcastWorkers()
1361
1387
 
1362
1388
  this.logger.warn(`The ${errorLabel} unexpectedly exited with code ${code}.`)
@@ -1377,7 +1403,7 @@ export class Runtime extends EventEmitter {
1377
1403
  }
1378
1404
  )
1379
1405
  } else {
1380
- this.emit('application:worker:unvailable', eventPayload)
1406
+ this.emitAndNotify('application:worker:unvailable', eventPayload)
1381
1407
  this.logger.warn(`The ${errorLabel} is no longer available.`)
1382
1408
  }
1383
1409
  }
@@ -1407,8 +1433,12 @@ export class Runtime extends EventEmitter {
1407
1433
  worker[kITC].listen()
1408
1434
 
1409
1435
  // Forward events from the worker
1436
+ // Do not use emitAndNotify here since we don't want to forward unknown events
1410
1437
  worker[kITC].on('event', ({ event, payload }) => {
1411
- this.emit(`application:worker:event:${event}`, { ...eventPayload, payload })
1438
+ event = `application:worker:event:${event}`
1439
+
1440
+ this.emit(event, ...payload)
1441
+ this.logger.trace({ event, payload }, 'Runtime event')
1412
1442
  })
1413
1443
 
1414
1444
  // Only activate watch for the first instance
@@ -1418,7 +1448,7 @@ export class Runtime extends EventEmitter {
1418
1448
  // so that applications can eventually manually trigger a restart. This mechanism is current
1419
1449
  // used by the gateway.
1420
1450
  worker[kITC].on('changed', async () => {
1421
- this.emit('application:worker:changed', eventPayload)
1451
+ this.emitAndNotify('application:worker:changed', eventPayload)
1422
1452
 
1423
1453
  try {
1424
1454
  const wasStarted = worker[kWorkerStatus].startsWith('start')
@@ -1429,7 +1459,7 @@ export class Runtime extends EventEmitter {
1429
1459
  }
1430
1460
 
1431
1461
  this.logger.info(`The application "${applicationId}" has been successfully reloaded ...`)
1432
- this.emit('application:worker:reloaded', eventPayload)
1462
+ this.emitAndNotify('application:worker:reloaded', eventPayload)
1433
1463
 
1434
1464
  if (applicationConfig.entrypoint) {
1435
1465
  this.#showUrl()
@@ -1457,7 +1487,7 @@ export class Runtime extends EventEmitter {
1457
1487
 
1458
1488
  worker[kConfig] = { ...applicationConfig, health, workers: workersCount }
1459
1489
  worker[kWorkerStatus] = 'init'
1460
- this.emit('application:worker:init', eventPayload)
1490
+ this.emitAndNotify('application:worker:init', eventPayload)
1461
1491
 
1462
1492
  return worker
1463
1493
  }
@@ -1501,7 +1531,7 @@ export class Runtime extends EventEmitter {
1501
1531
  health = { elu: -1, heapUsed: -1, heapTotal: -1 }
1502
1532
  }
1503
1533
 
1504
- this.emit('application:worker:health', {
1534
+ this.emitAndNotify('application:worker:health', {
1505
1535
  id: worker[kId],
1506
1536
  application: id,
1507
1537
  worker: index,
@@ -1530,7 +1560,7 @@ export class Runtime extends EventEmitter {
1530
1560
 
1531
1561
  if (unhealthyChecks === maxUnhealthyChecks) {
1532
1562
  try {
1533
- this.emit('application:worker:unhealthy', { application: id, worker: index })
1563
+ this.emitAndNotify('application:worker:unhealthy', { application: id, worker: index })
1534
1564
 
1535
1565
  this.logger.error(
1536
1566
  { elu: health.elu, maxELU, memoryUsage: health.heapUsed, maxMemoryUsage: maxHeapUsed },
@@ -1582,7 +1612,7 @@ export class Runtime extends EventEmitter {
1582
1612
  }
1583
1613
 
1584
1614
  worker[kWorkerStatus] = 'starting'
1585
- this.emit('application:worker:starting', eventPayload)
1615
+ this.emitAndNotify('application:worker:starting', eventPayload)
1586
1616
 
1587
1617
  try {
1588
1618
  let workerUrl
@@ -1590,7 +1620,7 @@ export class Runtime extends EventEmitter {
1590
1620
  workerUrl = await executeWithTimeout(sendViaITC(worker, 'start'), config.startTimeout)
1591
1621
 
1592
1622
  if (workerUrl === kTimeout) {
1593
- this.emit('application:worker:startTimeout', eventPayload)
1623
+ this.emitAndNotify('application:worker:startTimeout', eventPayload)
1594
1624
  this.logger.info(`The ${label} failed to start in ${config.startTimeout}ms. Forcefully killing the thread.`)
1595
1625
  worker.terminate()
1596
1626
  throw new ApplicationStartTimeoutError(id, config.startTimeout)
@@ -1606,7 +1636,7 @@ export class Runtime extends EventEmitter {
1606
1636
  }
1607
1637
 
1608
1638
  worker[kWorkerStatus] = 'started'
1609
- this.emit('application:worker:started', eventPayload)
1639
+ this.emitAndNotify('application:worker:started', eventPayload)
1610
1640
  this.#broadcastWorkers()
1611
1641
 
1612
1642
  if (!silent) {
@@ -1645,7 +1675,7 @@ export class Runtime extends EventEmitter {
1645
1675
  }
1646
1676
  }
1647
1677
 
1648
- this.emit('application:worker:start:error', { ...eventPayload, error })
1678
+ this.emitAndNotify('application:worker:start:error', { ...eventPayload, error })
1649
1679
 
1650
1680
  if (error.code !== 'PLT_RUNTIME_APPLICATION_START_TIMEOUT') {
1651
1681
  this.logger.error({ err: ensureLoggableError(error) }, `Failed to start ${label}: ${error.message}`)
@@ -1659,7 +1689,7 @@ export class Runtime extends EventEmitter {
1659
1689
 
1660
1690
  if (bootstrapAttempt++ >= MAX_BOOTSTRAP_ATTEMPTS || restartOnError === 0) {
1661
1691
  this.logger.error(`Failed to start ${label} after ${MAX_BOOTSTRAP_ATTEMPTS} attempts.`)
1662
- this.emit('application:worker:start:failed', { ...eventPayload, error })
1692
+ this.emitAndNotify('application:worker:start:failed', { ...eventPayload, error })
1663
1693
  throw error
1664
1694
  }
1665
1695
 
@@ -1695,7 +1725,7 @@ export class Runtime extends EventEmitter {
1695
1725
 
1696
1726
  worker[kWorkerStatus] = 'stopping'
1697
1727
  worker[kITC].removeAllListeners('changed')
1698
- this.emit('application:worker:stopping', eventPayload)
1728
+ this.emitAndNotify('application:worker:stopping', eventPayload)
1699
1729
 
1700
1730
  const label = this.#workerExtendedLabel(id, index, workersCount)
1701
1731
 
@@ -1710,7 +1740,7 @@ export class Runtime extends EventEmitter {
1710
1740
  try {
1711
1741
  await executeWithTimeout(sendViaITC(worker, 'stop', { force: !!this.error, dependents }), exitTimeout)
1712
1742
  } catch (error) {
1713
- this.emit('application:worker:stop:error', eventPayload)
1743
+ this.emitAndNotify('application:worker:stop:error', eventPayload)
1714
1744
  this.logger.info({ error: ensureLoggableError(error) }, `Failed to stop ${label}. Killing a worker thread.`)
1715
1745
  } finally {
1716
1746
  worker[kITC].notify('application:worker:stop:processed')
@@ -1729,14 +1759,14 @@ export class Runtime extends EventEmitter {
1729
1759
 
1730
1760
  // If the worker didn't exit in time, kill it
1731
1761
  if (res === kTimeout) {
1732
- this.emit('application:worker:exit:timeout', eventPayload)
1762
+ this.emitAndNotify('application:worker:exit:timeout', eventPayload)
1733
1763
  await worker.terminate()
1734
1764
  }
1735
1765
 
1736
1766
  await this.#avoidOutOfOrderThreadLogs()
1737
1767
 
1738
1768
  worker[kWorkerStatus] = 'stopped'
1739
- this.emit('application:worker:stopped', eventPayload)
1769
+ this.emitAndNotify('application:worker:stopped', eventPayload)
1740
1770
  this.#broadcastWorkers()
1741
1771
  }
1742
1772
 
@@ -1814,11 +1844,16 @@ export class Runtime extends EventEmitter {
1814
1844
  await restartPromise
1815
1845
  }
1816
1846
 
1817
- async #replaceWorker (config, applicationConfig, workersCount, applicationId, index, worker) {
1847
+ async #replaceWorker (config, applicationConfig, workersCount, applicationId, index, worker, silent) {
1818
1848
  const workerId = `${applicationId}:${index}`
1849
+ const label = this.#workerExtendedLabel(applicationId, index, workersCount)
1819
1850
  let newWorker
1820
1851
 
1821
1852
  try {
1853
+ if (!silent) {
1854
+ this.logger.debug(`Preparing to start a replacement for ${label} ...`)
1855
+ }
1856
+
1822
1857
  // Create a new worker
1823
1858
  newWorker = await this.#setupWorker(config, applicationConfig, workersCount, applicationId, index, false)
1824
1859
 
@@ -1845,6 +1880,9 @@ export class Runtime extends EventEmitter {
1845
1880
  throw e
1846
1881
  }
1847
1882
 
1883
+ if (!silent) {
1884
+ this.logger.debug(`Preparing to stop the old version of ${label} ...`)
1885
+ }
1848
1886
  await this.#stopWorker(workersCount, applicationId, index, false, worker, [])
1849
1887
  }
1850
1888
 
@@ -1952,7 +1990,7 @@ export class Runtime extends EventEmitter {
1952
1990
  }
1953
1991
 
1954
1992
  context.transferList = [port2]
1955
- this.emit('application:worker:messagingChannel', { application, worker })
1993
+ this.emitAndNotify('application:worker:messagingChannel', { application, worker })
1956
1994
  return port2
1957
1995
  }
1958
1996
 
@@ -23,6 +23,13 @@ import { setupITC } from './itc.js'
23
23
  import { SharedContext } from './shared-context.js'
24
24
  import { kId, kITC, kStderrMarker } from './symbols.js'
25
25
 
26
+ class ForwardingEventEmitter extends EventEmitter {
27
+ emitAndNotify (event, ...args) {
28
+ globalThis.platformatic.itc.notify('event', { event, payload: args })
29
+ return this.emit(event, ...args)
30
+ }
31
+ }
32
+
26
33
  function handleUnhandled (app, type, err) {
27
34
  const label =
28
35
  workerData.worker.count > 1
@@ -103,7 +110,7 @@ async function main () {
103
110
  globalThis[kId] = threadId
104
111
  globalThis.platformatic = Object.assign(globalThis.platformatic ?? {}, {
105
112
  logger: createLogger(),
106
- events: new EventEmitter()
113
+ events: new ForwardingEventEmitter()
107
114
  })
108
115
 
109
116
  const config = workerData.config
@@ -217,6 +224,7 @@ async function main () {
217
224
  // Setup interaction with parent port
218
225
  const itc = setupITC(controller, application, threadDispatcher, sharedContext)
219
226
  globalThis[kITC] = itc
227
+ globalThis.platformatic.itc = itc
220
228
 
221
229
  itc.notify('init')
222
230
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@platformatic/runtime",
3
- "version": "3.5.0",
3
+ "version": "3.6.0",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -34,14 +34,14 @@
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/gateway": "3.5.0",
38
- "@platformatic/node": "3.5.0",
39
- "@platformatic/composer": "3.5.0",
40
- "@platformatic/db": "3.5.0",
41
- "@platformatic/service": "3.5.0",
42
- "@platformatic/sql-graphql": "3.5.0",
43
- "@platformatic/wattpm-pprof-capture": "3.5.0",
44
- "@platformatic/sql-mapper": "3.5.0"
37
+ "@platformatic/composer": "3.6.0",
38
+ "@platformatic/db": "3.6.0",
39
+ "@platformatic/gateway": "3.6.0",
40
+ "@platformatic/node": "3.6.0",
41
+ "@platformatic/service": "3.6.0",
42
+ "@platformatic/sql-mapper": "3.6.0",
43
+ "@platformatic/wattpm-pprof-capture": "3.6.0",
44
+ "@platformatic/sql-graphql": "3.6.0"
45
45
  },
46
46
  "dependencies": {
47
47
  "@fastify/accepts": "^5.0.0",
@@ -52,7 +52,7 @@
52
52
  "@platformatic/undici-cache-memory": "^0.8.1",
53
53
  "@watchable/unpromise": "^1.0.2",
54
54
  "change-case-all": "^2.1.0",
55
- "close-with-grace": "^2.2.0",
55
+ "close-with-grace": "^2.3.0",
56
56
  "colorette": "^2.0.20",
57
57
  "cron": "^4.1.0",
58
58
  "debounce": "^2.0.0",
@@ -71,12 +71,12 @@
71
71
  "undici": "^7.0.0",
72
72
  "undici-thread-interceptor": "^0.14.0",
73
73
  "ws": "^8.16.0",
74
- "@platformatic/foundation": "3.5.0",
75
- "@platformatic/generators": "3.5.0",
76
- "@platformatic/basic": "3.5.0",
77
- "@platformatic/itc": "3.5.0",
78
- "@platformatic/metrics": "3.5.0",
79
- "@platformatic/telemetry": "3.5.0"
74
+ "@platformatic/basic": "3.6.0",
75
+ "@platformatic/foundation": "3.6.0",
76
+ "@platformatic/generators": "3.6.0",
77
+ "@platformatic/metrics": "3.6.0",
78
+ "@platformatic/itc": "3.6.0",
79
+ "@platformatic/telemetry": "3.6.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.5.0.json",
2
+ "$id": "https://schemas.platformatic.dev/@platformatic/runtime/3.6.0.json",
3
3
  "$schema": "http://json-schema.org/draft-07/schema#",
4
4
  "title": "Platformatic Runtime Config",
5
5
  "type": "object",
@@ -926,6 +926,18 @@
926
926
  ],
927
927
  "default": 1
928
928
  },
929
+ "workersRestartDelay": {
930
+ "anyOf": [
931
+ {
932
+ "type": "number",
933
+ "minimum": 0
934
+ },
935
+ {
936
+ "type": "string"
937
+ }
938
+ ],
939
+ "default": 0
940
+ },
929
941
  "logger": {
930
942
  "type": "object",
931
943
  "properties": {