@platformatic/runtime 2.49.0 → 2.51.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
@@ -5,7 +5,7 @@
5
5
  * and run json-schema-to-typescript to regenerate this file.
6
6
  */
7
7
 
8
- export type HttpsSchemasPlatformaticDevPlatformaticRuntime2490Json = {
8
+ export type HttpsSchemasPlatformaticDevPlatformaticRuntime2510Json = {
9
9
  [k: string]: unknown;
10
10
  } & {
11
11
  $schema?: string;
@@ -186,6 +186,19 @@ export type HttpsSchemasPlatformaticDevPlatformaticRuntime2490Json = {
186
186
  body?: string;
187
187
  };
188
188
  };
189
+ liveness?:
190
+ | boolean
191
+ | {
192
+ endpoint?: string;
193
+ success?: {
194
+ statusCode?: number;
195
+ body?: string;
196
+ };
197
+ fail?: {
198
+ statusCode?: number;
199
+ body?: string;
200
+ };
201
+ };
189
202
  additionalProperties?: never;
190
203
  [k: string]: unknown;
191
204
  };
package/lib/errors.js CHANGED
@@ -20,6 +20,7 @@ module.exports = {
20
20
  FailedToRetrieveMetaError: createError(`${ERROR_PREFIX}_FAILED_TO_RETRIEVE_META`, 'Failed to retrieve metadata for service with id "%s": %s'),
21
21
  FailedToRetrieveMetricsError: createError(`${ERROR_PREFIX}_FAILED_TO_RETRIEVE_METRICS`, 'Failed to retrieve metrics for service with id "%s": %s'),
22
22
  FailedToRetrieveHealthError: createError(`${ERROR_PREFIX}_FAILED_TO_RETRIEVE_HEALTH`, 'Failed to retrieve health for service with id "%s": %s'),
23
+ FailedToPerformCustomHealthCheckError: createError(`${ERROR_PREFIX}_FAILED_TO_PERFORM_CUSTOM_HEALTH_CHECK`, 'Failed to perform custom healthcheck for service with id "%s": %s'),
23
24
  ApplicationAlreadyStartedError: createError(`${ERROR_PREFIX}_APPLICATION_ALREADY_STARTED`, 'Application is already started'),
24
25
  ApplicationNotStartedError: createError(`${ERROR_PREFIX}_APPLICATION_NOT_STARTED`, 'Application has not been started'),
25
26
  ConfigPathMustBeStringError: createError(`${ERROR_PREFIX}_CONFIG_PATH_MUST_BE_STRING`, 'Config path must be a string'),
@@ -10,6 +10,11 @@ const DEFAULT_READINESS_SUCCESS_STATUS_CODE = 200
10
10
  const DEFAULT_READINESS_SUCCESS_BODY = 'OK'
11
11
  const DEFAULT_READINESS_FAIL_STATUS_CODE = 500
12
12
  const DEFAULT_READINESS_FAIL_BODY = 'ERR'
13
+ const DEFAULT_LIVENESS_ENDPOINT = '/status'
14
+ const DEFAULT_LIVENESS_SUCCESS_STATUS_CODE = 200
15
+ const DEFAULT_LIVENESS_SUCCESS_BODY = 'OK'
16
+ const DEFAULT_LIVENESS_FAIL_STATUS_CODE = 500
17
+ const DEFAULT_LIVENESS_FAIL_BODY = 'ERR'
13
18
 
14
19
  async function checkReadiness (runtime) {
15
20
  const workers = await runtime.getWorkers()
@@ -22,6 +27,16 @@ async function checkReadiness (runtime) {
22
27
  return true
23
28
  }
24
29
 
30
+ async function checkLiveness (runtime) {
31
+ if (!(await checkReadiness(runtime))) {
32
+ return false
33
+ }
34
+
35
+ const checks = await runtime.getCustomHealthChecks()
36
+
37
+ return Object.values(checks).every(check => check)
38
+ }
39
+
25
40
  async function startPrometheusServer (runtime, opts) {
26
41
  if (opts.enabled === false) {
27
42
  return
@@ -76,11 +91,33 @@ async function startPrometheusServer (runtime, opts) {
76
91
  const ready = await checkReadiness(runtime)
77
92
 
78
93
  if (ready) {
79
- reply.status(successStatusCode)
80
- return successBody
94
+ reply.status(successStatusCode).send(successBody)
95
+ } else {
96
+ reply.status(failStatusCode).send(failBody)
97
+ }
98
+ },
99
+ })
100
+ }
101
+
102
+ if (opts.liveness !== false) {
103
+ const successStatusCode = opts.liveness?.success?.statusCode ?? DEFAULT_LIVENESS_SUCCESS_STATUS_CODE
104
+ const successBody = opts.liveness?.success?.body ?? DEFAULT_LIVENESS_SUCCESS_BODY
105
+ const failStatusCode = opts.liveness?.fail?.statusCode ?? DEFAULT_LIVENESS_FAIL_STATUS_CODE
106
+ const failBody = opts.liveness?.fail?.body ?? DEFAULT_LIVENESS_FAIL_BODY
107
+
108
+ promServer.route({
109
+ url: opts.liveness?.endpoint ?? DEFAULT_LIVENESS_ENDPOINT,
110
+ method: 'GET',
111
+ logLevel: 'warn',
112
+ handler: async (req, reply) => {
113
+ reply.type('text/plain')
114
+
115
+ const live = await checkLiveness(runtime)
116
+
117
+ if (live) {
118
+ reply.status(successStatusCode).send(successBody)
81
119
  } else {
82
- reply.status(failStatusCode)
83
- return failBody
120
+ reply.status(failStatusCode).send(failBody)
84
121
  }
85
122
  },
86
123
  })
package/lib/runtime.js CHANGED
@@ -648,6 +648,21 @@ class Runtime extends EventEmitter {
648
648
  return status
649
649
  }
650
650
 
651
+ async getCustomHealthChecks () {
652
+ const status = {}
653
+
654
+ for (const [service, { count }] of Object.entries(this.#workers.configuration)) {
655
+ for (let i = 0; i < count; i++) {
656
+ const label = `${service}:${i}`
657
+ const worker = this.#workers.get(label)
658
+
659
+ status[label] = await sendViaITC(worker, 'getCustomHealthCheck')
660
+ }
661
+ }
662
+
663
+ return status
664
+ }
665
+
651
666
  async getServiceDetails (id, allowUnloaded = false) {
652
667
  let service
653
668
 
package/lib/schema.js CHANGED
@@ -409,6 +409,34 @@ const platformaticRuntimeSchema = {
409
409
  }
410
410
  ]
411
411
  },
412
+ liveness: {
413
+ anyOf: [
414
+ { type: 'boolean' },
415
+ {
416
+ type: 'object',
417
+ properties: {
418
+ endpoint: { type: 'string' },
419
+ success: {
420
+ type: 'object',
421
+ properties: {
422
+ statusCode: { type: 'number' },
423
+ body: { type: 'string' }
424
+ },
425
+ additionalProperties: false
426
+ },
427
+ fail: {
428
+ type: 'object',
429
+ properties: {
430
+ statusCode: { type: 'number' },
431
+ body: { type: 'string' }
432
+ },
433
+ additionalProperties: false
434
+ }
435
+ },
436
+ additionalProperties: false
437
+ }
438
+ ]
439
+ },
412
440
  additionalProperties: false
413
441
  }
414
442
  }
@@ -16,6 +16,7 @@ const defaultStackable = {
16
16
  getDispatchTarget: () => null,
17
17
  getOpenapiSchema: () => null,
18
18
  getGraphqlSchema: () => null,
19
+ getCustomHealthCheck: () => null,
19
20
  getMeta: () => ({}),
20
21
  getMetrics: () => null,
21
22
  inject: () => {
package/lib/worker/itc.js CHANGED
@@ -166,6 +166,14 @@ function setupITC (app, service, dispatcher) {
166
166
  } catch (err) {
167
167
  throw new errors.FailedToRetrieveHealthError(service.id, err.message)
168
168
  }
169
+ },
170
+
171
+ async getCustomHealthCheck () {
172
+ try {
173
+ return await app.stackable.getCustomHealthCheck()
174
+ } catch (err) {
175
+ throw new errors.FailedToPerformCustomHealthCheckError(service.id, err.message)
176
+ }
169
177
  }
170
178
  }
171
179
  })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@platformatic/runtime",
3
- "version": "2.49.0",
3
+ "version": "2.51.0",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -37,12 +37,12 @@
37
37
  "typescript": "^5.5.4",
38
38
  "undici-oidc-interceptor": "^0.5.0",
39
39
  "why-is-node-running": "^2.2.2",
40
- "@platformatic/composer": "2.49.0",
41
- "@platformatic/db": "2.49.0",
42
- "@platformatic/service": "2.49.0",
43
- "@platformatic/node": "2.49.0",
44
- "@platformatic/sql-graphql": "2.49.0",
45
- "@platformatic/sql-mapper": "2.49.0"
40
+ "@platformatic/composer": "2.51.0",
41
+ "@platformatic/db": "2.51.0",
42
+ "@platformatic/sql-graphql": "2.51.0",
43
+ "@platformatic/sql-mapper": "2.51.0",
44
+ "@platformatic/service": "2.51.0",
45
+ "@platformatic/node": "2.51.0"
46
46
  },
47
47
  "dependencies": {
48
48
  "@fastify/accepts": "^5.0.0",
@@ -76,13 +76,13 @@
76
76
  "undici": "^7.0.0",
77
77
  "undici-thread-interceptor": "^0.13.1",
78
78
  "ws": "^8.16.0",
79
- "@platformatic/basic": "2.49.0",
80
- "@platformatic/config": "2.49.0",
81
- "@platformatic/generators": "2.49.0",
82
- "@platformatic/itc": "2.49.0",
83
- "@platformatic/telemetry": "2.49.0",
84
- "@platformatic/ts-compiler": "2.49.0",
85
- "@platformatic/utils": "2.49.0"
79
+ "@platformatic/basic": "2.51.0",
80
+ "@platformatic/config": "2.51.0",
81
+ "@platformatic/generators": "2.51.0",
82
+ "@platformatic/itc": "2.51.0",
83
+ "@platformatic/utils": "2.51.0",
84
+ "@platformatic/telemetry": "2.51.0",
85
+ "@platformatic/ts-compiler": "2.51.0"
86
86
  },
87
87
  "scripts": {
88
88
  "test": "npm run lint && borp --concurrency=1 --timeout=300000 && tsd",
package/schema.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "$id": "https://schemas.platformatic.dev/@platformatic/runtime/2.49.0.json",
2
+ "$id": "https://schemas.platformatic.dev/@platformatic/runtime/2.51.0.json",
3
3
  "$schema": "http://json-schema.org/draft-07/schema#",
4
4
  "type": "object",
5
5
  "properties": {
@@ -1194,6 +1194,46 @@
1194
1194
  }
1195
1195
  ]
1196
1196
  },
1197
+ "liveness": {
1198
+ "anyOf": [
1199
+ {
1200
+ "type": "boolean"
1201
+ },
1202
+ {
1203
+ "type": "object",
1204
+ "properties": {
1205
+ "endpoint": {
1206
+ "type": "string"
1207
+ },
1208
+ "success": {
1209
+ "type": "object",
1210
+ "properties": {
1211
+ "statusCode": {
1212
+ "type": "number"
1213
+ },
1214
+ "body": {
1215
+ "type": "string"
1216
+ }
1217
+ },
1218
+ "additionalProperties": false
1219
+ },
1220
+ "fail": {
1221
+ "type": "object",
1222
+ "properties": {
1223
+ "statusCode": {
1224
+ "type": "number"
1225
+ },
1226
+ "body": {
1227
+ "type": "string"
1228
+ }
1229
+ },
1230
+ "additionalProperties": false
1231
+ }
1232
+ },
1233
+ "additionalProperties": false
1234
+ }
1235
+ ]
1236
+ },
1197
1237
  "additionalProperties": false
1198
1238
  }
1199
1239
  }