@platformatic/runtime 1.47.0 → 1.48.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,4 @@
1
+ {
2
+ "name": "test-runtime-package",
3
+ "version": "1.0.42"
4
+ }
@@ -0,0 +1,23 @@
1
+ {
2
+ "$schema": "https://platformatic.dev/schemas/v1.22.0/runtime",
3
+ "entrypoint": "service-1",
4
+ "allowCycles": true,
5
+ "hotReload": false,
6
+ "autoload": {
7
+ "path": "./services"
8
+ },
9
+ "server": {
10
+ "hostname": "127.0.0.1",
11
+ "port": 0
12
+ },
13
+ "managementApi": {
14
+ "logs": {
15
+ "maxSize": 15
16
+ }
17
+ },
18
+ "metrics": {
19
+ "labels": {
20
+ "foo": "bar"
21
+ }
22
+ }
23
+ }
@@ -0,0 +1,12 @@
1
+ {
2
+ "$schema": "https://platformatic.dev/schemas/v1.22.0/service",
3
+ "service": {
4
+ "openapi": true
5
+ },
6
+ "plugins": {
7
+ "paths": [
8
+ "plugin.js"
9
+ ]
10
+ },
11
+ "watch": true
12
+ }
@@ -0,0 +1,15 @@
1
+ 'use strict'
2
+
3
+ /** @param {import('fastify').FastifyInstance} app */
4
+ module.exports = async function (app) {
5
+ app.get('/hello', async () => {
6
+ return { service: 'service-2' }
7
+ })
8
+
9
+ app.get('/large-logs', async (req) => {
10
+ const largeLog = 'a'.repeat(100)
11
+ for (let i = 0; i < 500000; i++) {
12
+ app.log.trace(largeLog)
13
+ }
14
+ })
15
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "$schema": "https://platformatic.dev/schemas/v1.22.0/service",
3
+ "service": {
4
+ "openapi": true
5
+ },
6
+ "plugins": {
7
+ "paths": ["plugin.js"]
8
+ }
9
+ }
@@ -0,0 +1,8 @@
1
+ 'use strict'
2
+
3
+ /** @param {import('fastify').FastifyInstance} app */
4
+ module.exports = async function (app, options) {
5
+ app.get('/hello', async () => {
6
+ return { service: 'service-2' }
7
+ })
8
+ }
@@ -0,0 +1,4 @@
1
+ CREATE TABLE IF NOT EXISTS movies (
2
+ id INTEGER PRIMARY KEY,
3
+ title TEXT NOT NULL
4
+ );
@@ -0,0 +1,5 @@
1
+ {
2
+ "name": "@myscope/myname",
3
+ "version": "0.0.1",
4
+ "description": "test package.json"
5
+ }
@@ -0,0 +1,29 @@
1
+ {
2
+ "$schema": "https://platformatic.dev/schemas/v0.22.0/db",
3
+ "server": {
4
+ "hostname": "127.0.0.1",
5
+ "port": 0
6
+ },
7
+ "migrations": {
8
+ "dir": "migrations",
9
+ "table": "versions",
10
+ "autoApply": true
11
+ },
12
+ "types": {
13
+ "autogenerate": false
14
+ },
15
+ "db": {
16
+ "connectionString": "sqlite://db.sqlite",
17
+ "graphql": true,
18
+ "ignore": {
19
+ "versions": true
20
+ },
21
+ "events": false
22
+ },
23
+ "plugins": {
24
+ "paths": [
25
+ "plugin.js"
26
+ ]
27
+ },
28
+ "watch": false
29
+ }
@@ -0,0 +1,12 @@
1
+ 'use strict'
2
+
3
+ /** @param {import('fastify').FastifyInstance} app */
4
+ module.exports = async function (app) {
5
+ app.get('/async_crash', async () => {
6
+ setImmediate(() => {
7
+ throw new Error('boom')
8
+ })
9
+
10
+ return 'ok'
11
+ })
12
+ }
package/lib/api.js CHANGED
@@ -6,21 +6,30 @@ const { createFastifyInterceptor } = require('fastify-undici-dispatcher')
6
6
  const { PlatformaticApp } = require('./app')
7
7
  const errors = require('./errors')
8
8
  const { printSchema } = require('graphql')
9
+ const { Bus } = require('@platformatic/bus')
9
10
 
10
11
  class RuntimeApi {
11
12
  #services
12
13
  #dispatcher
13
14
  #interceptor
14
15
  #logger
16
+ #bus
15
17
 
16
18
  constructor (config, logger, loaderPort, composedInterceptors = []) {
17
19
  this.#services = new Map()
18
20
  this.#logger = logger
21
+ this.#setupBus()
19
22
  const telemetryConfig = config.telemetry
23
+ const metricsConfig = config.metrics
20
24
 
21
25
  for (let i = 0; i < config.services.length; ++i) {
22
26
  const service = config.services[i]
23
- const serviceTelemetryConfig = telemetryConfig ? { ...telemetryConfig, serviceName: `${telemetryConfig.serviceName}-${service.id}` } : null
27
+ const serviceTelemetryConfig = telemetryConfig
28
+ ? {
29
+ ...telemetryConfig,
30
+ serviceName: `${telemetryConfig.serviceName}-${service.id}`
31
+ }
32
+ : null
24
33
 
25
34
  // If the service is an entrypoint and runtime server config is defined, use it.
26
35
  let serverConfig = null
@@ -34,7 +43,7 @@ class RuntimeApi {
34
43
  }
35
44
  }
36
45
 
37
- const app = new PlatformaticApp(service, loaderPort, logger, serviceTelemetryConfig, serverConfig, !!config.managementApi)
46
+ const app = new PlatformaticApp(service, loaderPort, logger, serviceTelemetryConfig, serverConfig, !!config.managementApi, metricsConfig)
38
47
 
39
48
  this.#services.set(service.id, app)
40
49
  }
@@ -155,6 +164,7 @@ class RuntimeApi {
155
164
  const serviceUrl = new URL(service.appConfig.localUrl)
156
165
  this.#interceptor.route(serviceUrl.host, service.server)
157
166
  }
167
+ this.#bus.broadcast('runtime:services:started')
158
168
  return entrypointUrl
159
169
  }
160
170
 
@@ -172,6 +182,7 @@ class RuntimeApi {
172
182
  }
173
183
  }
174
184
  await Promise.all(stopServiceReqs)
185
+ this.#bus.broadcast('runtime:services:stopped')
175
186
  }
176
187
 
177
188
  async #restartServices () {
@@ -191,6 +202,7 @@ class RuntimeApi {
191
202
  const serviceUrl = new URL(service.appConfig.localUrl)
192
203
  this.#interceptor.route(serviceUrl.host, service.server)
193
204
  }
205
+ this.#bus.broadcast('runtime:services:restarted')
194
206
  return entrypointUrl
195
207
  }
196
208
 
@@ -308,30 +320,30 @@ class RuntimeApi {
308
320
  }
309
321
 
310
322
  async #getMetrics ({ format }) {
311
- let entrypoint = null
323
+ let metrics = null
324
+
312
325
  for (const service of this.#services.values()) {
313
- if (service.appConfig.entrypoint) {
314
- entrypoint = service
315
- break
326
+ const serviceId = service.appConfig.id
327
+ const serviceStatus = service.getStatus()
328
+ if (serviceStatus !== 'started') {
329
+ throw new errors.ServiceNotStartedError(serviceId)
316
330
  }
317
- }
318
331
 
319
- const entrypointStatus = entrypoint.getStatus()
320
- if (entrypointStatus !== 'started') {
321
- throw new errors.ServiceNotStartedError(entrypoint.id)
322
- }
332
+ const promRegister = service.server.metrics?.client?.register
323
333
 
324
- const promRegister = entrypoint.server.metrics?.client?.register
325
- if (!promRegister) {
326
- return { metrics: null }
334
+ if (promRegister) {
335
+ if (metrics === null) {
336
+ metrics = format === 'json' ? [] : ''
337
+ }
338
+ if (format === 'json') {
339
+ metrics.push(...await promRegister.getMetricsAsJSON())
340
+ } else {
341
+ const serviceMetrics = await promRegister.metrics()
342
+ metrics += serviceMetrics
343
+ }
344
+ }
327
345
  }
328
346
 
329
- // All runtime services shares the same metrics registry.
330
- // Getting metrics from the entrypoint returns all metrics.
331
- const metrics = format === 'json'
332
- ? await promRegister.getMetricsAsJSON()
333
- : await promRegister.metrics()
334
-
335
347
  return { metrics }
336
348
  }
337
349
 
@@ -344,6 +356,7 @@ class RuntimeApi {
344
356
  } else {
345
357
  await service.start()
346
358
  }
359
+ this.#bus.broadcast('runtime:service:started', id)
347
360
  }
348
361
 
349
362
  async #stopService ({ id }) {
@@ -355,6 +368,7 @@ class RuntimeApi {
355
368
  }
356
369
 
357
370
  await service.stop()
371
+ this.#bus.broadcast('runtime:service:stopped', id)
358
372
  }
359
373
 
360
374
  async #inject ({ id, injectParams }) {
@@ -374,6 +388,10 @@ class RuntimeApi {
374
388
  body: res.body
375
389
  }
376
390
  }
391
+
392
+ #setupBus (config) {
393
+ this.#bus = new Bus('$root')
394
+ }
377
395
  }
378
396
 
379
397
  module.exports = RuntimeApi
package/lib/app.js CHANGED
@@ -21,8 +21,9 @@ class PlatformaticApp extends EventEmitter {
21
21
  #serverConfig
22
22
  #debouncedRestart
23
23
  #hasManagementApi
24
+ #metricsConfig
24
25
 
25
- constructor (appConfig, loaderPort, logger, telemetryConfig, serverConfig, hasManagementApi) {
26
+ constructor (appConfig, loaderPort, logger, telemetryConfig, serverConfig, hasManagementApi, metricsConfig) {
26
27
  super()
27
28
  this.appConfig = appConfig
28
29
  this.config = null
@@ -38,6 +39,7 @@ class PlatformaticApp extends EventEmitter {
38
39
  name: this.appConfig.id
39
40
  })
40
41
  this.#telemetryConfig = telemetryConfig
42
+ this.#metricsConfig = metricsConfig
41
43
  this.#serverConfig = serverConfig
42
44
 
43
45
  /* c8 ignore next 4 */
@@ -111,6 +113,7 @@ class PlatformaticApp extends EventEmitter {
111
113
  this.server = await buildServer({
112
114
  app: this.config.app,
113
115
  ...config,
116
+ id: this.appConfig.id,
114
117
  configManager
115
118
  })
116
119
  } catch (err) {
@@ -250,9 +253,17 @@ class PlatformaticApp extends EventEmitter {
250
253
  const { configManager } = this.config
251
254
  configManager.update({
252
255
  ...configManager.current,
253
- telemetry: this.#telemetryConfig
256
+ telemetry: this.#telemetryConfig,
257
+ metrics: this.#metricsConfig
254
258
  })
255
259
 
260
+ if (configManager.current.metrics !== false) {
261
+ configManager.update({
262
+ ...configManager.current,
263
+ metrics: this.#metricsConfig
264
+ })
265
+ }
266
+
256
267
  if (this.#serverConfig) {
257
268
  configManager.update({
258
269
  ...configManager.current,
package/lib/schema.js CHANGED
@@ -170,6 +170,10 @@ const platformaticRuntimeSchema = {
170
170
  },
171
171
  additionalProperties: false,
172
172
  required: ['username', 'password']
173
+ },
174
+ labels: {
175
+ type: 'object',
176
+ additionalProperties: { type: 'string' }
173
177
  }
174
178
  },
175
179
  additionalProperties: false
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@platformatic/runtime",
3
- "version": "1.47.0",
3
+ "version": "1.48.0",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -21,7 +21,7 @@
21
21
  "@fastify/formbody": "^7.4.0",
22
22
  "@matteo.collina/tspl": "^0.1.1",
23
23
  "borp": "^0.15.0",
24
- "c8": "^9.1.0",
24
+ "c8": "^10.0.0",
25
25
  "execa": "^8.0.1",
26
26
  "express": "^4.18.3",
27
27
  "fast-jwt": "^4.0.0",
@@ -34,8 +34,8 @@
34
34
  "typescript": "^5.4.2",
35
35
  "undici-oidc-interceptor": "^0.5.0",
36
36
  "why-is-node-running": "^2.2.2",
37
- "@platformatic/sql-graphql": "1.47.0",
38
- "@platformatic/sql-mapper": "1.47.0"
37
+ "@platformatic/sql-mapper": "1.48.0",
38
+ "@platformatic/sql-graphql": "1.48.0"
39
39
  },
40
40
  "dependencies": {
41
41
  "@fastify/error": "^3.4.1",
@@ -63,13 +63,14 @@
63
63
  "undici": "^6.9.0",
64
64
  "why-is-node-running": "^2.2.2",
65
65
  "ws": "^8.16.0",
66
- "@platformatic/composer": "1.47.0",
67
- "@platformatic/config": "1.47.0",
68
- "@platformatic/service": "1.47.0",
69
- "@platformatic/db": "1.47.0",
70
- "@platformatic/telemetry": "1.47.0",
71
- "@platformatic/generators": "1.47.0",
72
- "@platformatic/utils": "1.47.0"
66
+ "@platformatic/bus": "1.48.0",
67
+ "@platformatic/composer": "1.48.0",
68
+ "@platformatic/db": "1.48.0",
69
+ "@platformatic/config": "1.48.0",
70
+ "@platformatic/generators": "1.48.0",
71
+ "@platformatic/service": "1.48.0",
72
+ "@platformatic/telemetry": "1.48.0",
73
+ "@platformatic/utils": "1.48.0"
73
74
  },
74
75
  "standard": {
75
76
  "ignore": [