@platformatic/composer 2.42.0 → 2.44.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
@@ -3,6 +3,7 @@
3
3
  const deepEqual = require('fast-deep-equal')
4
4
  const ConfigManager = require('@platformatic/config')
5
5
  const { platformaticService, buildServer, buildStackable } = require('@platformatic/service')
6
+ const { isKeyEnabled } = require('@platformatic/utils')
6
7
 
7
8
  const { schema } = require('./lib/schema')
8
9
  const serviceProxy = require('./lib/proxy')
@@ -25,7 +26,7 @@ async function platformaticComposer (app, opts) {
25
26
  let hasGraphqlServices, hasOpenapiServices
26
27
 
27
28
  // When no services are specified, get the list from the runtime.
28
- await ensureServices(config)
29
+ await ensureServices(opts.context?.stackable?.serviceId, config)
29
30
 
30
31
  const { services } = configManager.current.composer
31
32
 
@@ -48,6 +49,15 @@ async function platformaticComposer (app, opts) {
48
49
  generatedComposedOpenAPI = await openApiGenerator(app, config.composer)
49
50
  }
50
51
 
52
+ if (isKeyEnabled('healthCheck', config.server)) {
53
+ if (typeof config.server.healthCheck !== 'object') {
54
+ config.server.healthCheck = {}
55
+ }
56
+
57
+ const stackable = opts.context.stackable
58
+ config.server.healthCheck.fn = stackable.isHealthy.bind(stackable)
59
+ }
60
+
51
61
  app.register(serviceProxy, { ...config.composer, context: opts.context })
52
62
  await app.register(platformaticService, { config: { ...config, openapi: false }, context: opts.context })
53
63
 
package/lib/proxy.js CHANGED
@@ -46,7 +46,7 @@ async function resolveServiceProxyParameters (service) {
46
46
 
47
47
  module.exports = fp(async function (app, opts) {
48
48
  const meta = { proxies: {} }
49
- const allDomains = opts.services.map(s => s.proxy?.hostname).filter(Boolean)
49
+ const hostnameLessProxies = []
50
50
 
51
51
  for (const service of opts.services) {
52
52
  if (!service.proxy) {
@@ -207,7 +207,7 @@ module.exports = fp(async function (app, opts) {
207
207
 
208
208
  return headers
209
209
  },
210
- onResponse: (request, reply, res) => {
210
+ onResponse: (_, reply, res) => {
211
211
  app.openTelemetry?.endHTTPSpanClient(reply.request.proxedCallSpan, {
212
212
  statusCode: reply.statusCode,
213
213
  headers: res.headers
@@ -217,8 +217,9 @@ module.exports = fp(async function (app, opts) {
217
217
  }
218
218
  }
219
219
 
220
+ hostnameLessProxies.push(proxyOptions)
221
+
220
222
  const host = service.proxy?.hostname
221
- const notHost = allDomains.filter(d => d !== host)
222
223
 
223
224
  if (host) {
224
225
  await app.register(httpProxy, {
@@ -226,14 +227,16 @@ module.exports = fp(async function (app, opts) {
226
227
  prefix: '/',
227
228
  constraints: { host }
228
229
  })
230
+ }
231
+ }
229
232
 
230
- await app.register(httpProxy, {
231
- ...proxyOptions,
232
- ...(notHost.length ? { constraints: { notHost } } : {})
233
- })
234
- } else {
235
- await app.register(httpProxy, proxyOptions)
233
+ const hostnames = opts.services.map(s => s.proxy?.hostname).filter(Boolean)
234
+ for (const options of hostnameLessProxies) {
235
+ if (hostnames.length > 0) {
236
+ options.constraints = { notHost: hostnames }
236
237
  }
238
+
239
+ await app.register(httpProxy, options)
237
240
  }
238
241
 
239
242
  opts.context?.stackable?.registerMeta(meta)
package/lib/stackable.js CHANGED
@@ -4,11 +4,12 @@ const { ServiceStackable } = require('@platformatic/service')
4
4
 
5
5
  const kITC = Symbol.for('plt.runtime.itc')
6
6
 
7
- async function ensureServices (config) {
7
+ async function ensureServices (composerId, config) {
8
8
  if (config.composer?.services?.length) {
9
9
  return
10
10
  }
11
11
 
12
+ composerId ??= globalThis.platformatic?.serviceId
12
13
  config.composer ??= {}
13
14
  config.composer.services ??= []
14
15
 
@@ -17,16 +18,17 @@ async function ensureServices (config) {
17
18
 
18
19
  if (services) {
19
20
  config.composer.services = services
20
- .filter(id => id !== globalThis.platformatic.serviceId) // Remove ourself
21
+ .filter(id => id !== composerId) // Remove ourself
21
22
  .map(id => ({ id, proxy: { prefix: `/${id}` } }))
22
23
  }
23
24
  }
24
25
 
25
26
  class ComposerStackable extends ServiceStackable {
26
27
  #meta
28
+ #dependencies
27
29
 
28
30
  async getBootstrapDependencies () {
29
- await ensureServices(this.configManager.current)
31
+ await ensureServices(this.serviceId, this.configManager.current)
30
32
 
31
33
  // We do not call init() on purpose, as we don't want to load the app just yet.
32
34
 
@@ -43,23 +45,10 @@ class ComposerStackable extends ServiceStackable {
43
45
  )
44
46
  }
45
47
 
48
+ this.#dependencies = dependencies
46
49
  return dependencies
47
50
  }
48
51
 
49
- async #parseDependency (id, urlString) {
50
- let url = this.#getServiceUrl(id)
51
-
52
- if (urlString) {
53
- const remoteUrl = await this.configManager.replaceEnv(urlString)
54
-
55
- if (remoteUrl) {
56
- url = remoteUrl
57
- }
58
- }
59
-
60
- return { id, url, local: url.endsWith('.plt.local') }
61
- }
62
-
63
52
  registerMeta (meta) {
64
53
  this.#meta = Object.assign(this.#meta ?? {}, meta)
65
54
  }
@@ -74,8 +63,36 @@ class ComposerStackable extends ServiceStackable {
74
63
  }
75
64
  }
76
65
 
77
- #getServiceUrl (id) {
78
- return `http://${id}.plt.local`
66
+ async isHealthy () {
67
+ // Still booting, assume healthy
68
+ if (!this.#dependencies) {
69
+ return true
70
+ }
71
+
72
+ const composedServices = this.#dependencies.map(dep => dep.id)
73
+ const workers = await globalThis[kITC].send('getWorkers')
74
+
75
+ for (const worker of Object.values(workers)) {
76
+ if (composedServices.includes(worker.service) && !worker.status.startsWith('start')) {
77
+ return false
78
+ }
79
+ }
80
+
81
+ return true
82
+ }
83
+
84
+ async #parseDependency (id, urlString) {
85
+ let url = `http://${id}.plt.local`
86
+
87
+ if (urlString) {
88
+ const remoteUrl = await this.configManager.replaceEnv(urlString)
89
+
90
+ if (remoteUrl) {
91
+ url = remoteUrl
92
+ }
93
+ }
94
+
95
+ return { id, url, local: url.endsWith('.plt.local') }
79
96
  }
80
97
  }
81
98
  module.exports = { ComposerStackable, ensureServices }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@platformatic/composer",
3
- "version": "2.42.0",
3
+ "version": "2.44.0",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -31,9 +31,9 @@
31
31
  "typescript": "^5.5.4",
32
32
  "why-is-node-running": "2",
33
33
  "ws": "^8.16.0",
34
- "@platformatic/client": "2.42.0",
35
- "@platformatic/config": "2.42.0",
36
- "@platformatic/db": "2.42.0"
34
+ "@platformatic/client": "2.44.0",
35
+ "@platformatic/config": "2.44.0",
36
+ "@platformatic/db": "2.44.0"
37
37
  },
38
38
  "dependencies": {
39
39
  "@fastify/error": "^4.0.0",
@@ -67,12 +67,12 @@
67
67
  "rfdc": "^1.3.1",
68
68
  "semgrator": "^0.3.0",
69
69
  "undici": "^7.0.0",
70
- "@platformatic/generators": "2.42.0",
71
- "@platformatic/scalar-theme": "2.42.0",
72
- "@platformatic/telemetry": "2.42.0",
73
- "@platformatic/service": "2.42.0",
74
- "@platformatic/utils": "^2.42.0",
75
- "@platformatic/config": "2.42.0"
70
+ "@platformatic/config": "2.44.0",
71
+ "@platformatic/generators": "2.44.0",
72
+ "@platformatic/scalar-theme": "2.44.0",
73
+ "@platformatic/telemetry": "2.44.0",
74
+ "@platformatic/service": "2.44.0",
75
+ "@platformatic/utils": "^2.44.0"
76
76
  },
77
77
  "scripts": {
78
78
  "test": "pnpm run lint && borp -T --timeout=300000 -c 1 && tsd",
package/schema.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "$id": "https://schemas.platformatic.dev/@platformatic/composer/2.42.0.json",
2
+ "$id": "https://schemas.platformatic.dev/@platformatic/composer/2.44.0.json",
3
3
  "$schema": "http://json-schema.org/draft-07/schema#",
4
4
  "title": "Platformatic Composer",
5
5
  "type": "object",