@platformatic/basic 3.29.1 → 3.31.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
@@ -31,7 +31,7 @@ export interface PlatformaticBasicConfig {
31
31
  };
32
32
  workersRestartDelay?: number | string;
33
33
  logger?: {
34
- level: (
34
+ level?: (
35
35
  | ("fatal" | "error" | "warn" | "info" | "debug" | "trace" | "silent")
36
36
  | {
37
37
  [k: string]: unknown;
@@ -414,6 +414,18 @@ export interface PlatformaticBasicConfig {
414
414
  [k: string]: string | [string, ...string[]];
415
415
  };
416
416
  };
417
+ compileCache?:
418
+ | boolean
419
+ | {
420
+ /**
421
+ * Enable Node.js module compile cache for faster startup
422
+ */
423
+ enabled?: boolean;
424
+ /**
425
+ * Directory to store compile cache. Defaults to .plt/compile-cache in app root
426
+ */
427
+ directory?: string;
428
+ };
417
429
  application?: {
418
430
  reuseTcpPorts?: boolean;
419
431
  workers?:
@@ -472,6 +484,18 @@ export interface PlatformaticBasicConfig {
472
484
  )[];
473
485
  [k: string]: unknown;
474
486
  };
487
+ compileCache?:
488
+ | boolean
489
+ | {
490
+ /**
491
+ * Enable Node.js module compile cache for faster startup
492
+ */
493
+ enabled?: boolean;
494
+ /**
495
+ * Directory to store compile cache. Defaults to .plt/compile-cache in app root
496
+ */
497
+ directory?: string;
498
+ };
475
499
  };
476
500
  };
477
501
  [k: string]: unknown;
package/lib/capability.js CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  kMetadata,
8
8
  kTimeout
9
9
  } from '@platformatic/foundation'
10
- import { client, collectMetrics, ensureMetricsGroup, setupOtlpExporter } from '@platformatic/metrics'
10
+ import { clearRegistry, client, collectThreadMetrics, ensureMetricsGroup, setupOtlpExporter } from '@platformatic/metrics'
11
11
  import { parseCommandString } from 'execa'
12
12
  import { spawn } from 'node:child_process'
13
13
  import { tracingChannel } from 'node:diagnostics_channel'
@@ -155,6 +155,37 @@ export class BaseCapability extends EventEmitter {
155
155
  // No-op by default
156
156
  }
157
157
 
158
+ async updateMetricsConfig (metricsConfig) {
159
+ // Transform applicationLabel to idLabel (same transformation as in worker/main.js)
160
+ const normalizedConfig = {
161
+ ...metricsConfig,
162
+ idLabel: metricsConfig.applicationLabel || 'applicationId'
163
+ }
164
+ this.context.metricsConfig = normalizedConfig
165
+
166
+ // If running in subprocess mode, send the update to the child process
167
+ if (this.childManager && this.clientWs) {
168
+ await this.childManager.send(this.clientWs, 'updateMetricsConfig', {
169
+ applicationId: this.applicationId,
170
+ workerId: this.workerId,
171
+ metricsConfig: normalizedConfig
172
+ })
173
+ return
174
+ }
175
+
176
+ if (this.metricsRegistry) {
177
+ // We must clear the registry to stop prom-client from collecting metrics in the background,
178
+ // and because prom-client doesn't support changing labels on existing metrics.
179
+ // This will lose all previously collected metrics.
180
+ clearRegistry(this.metricsRegistry)
181
+
182
+ if (metricsConfig.enabled !== false) {
183
+ this.#metricsCollected = false
184
+ await this._collectMetrics()
185
+ }
186
+ }
187
+ }
188
+
158
189
  start () {
159
190
  throw new Error('BaseCapability.start must be overriden by the subclasses')
160
191
  }
@@ -547,7 +578,8 @@ export class BaseCapability extends EventEmitter {
547
578
  backlog: this.serverConfig.backlog
548
579
  }
549
580
  : {},
550
- telemetryConfig: this.telemetryConfig
581
+ telemetryConfig: this.telemetryConfig,
582
+ compileCache: this.config.compileCache ?? this.runtimeConfig?.compileCache
551
583
  }
552
584
  }
553
585
 
@@ -708,7 +740,9 @@ export class BaseCapability extends EventEmitter {
708
740
  return
709
741
  }
710
742
 
711
- await collectMetrics(this.applicationId, this.workerId, metricsConfig, this.metricsRegistry)
743
+ // Use thread-specific metrics collection - process-level metrics are collected
744
+ // by the main runtime thread and duplicated with worker labels
745
+ await collectThreadMetrics(this.applicationId, this.workerId, metricsConfig, this.metricsRegistry)
712
746
  }
713
747
 
714
748
  #setHttpCacheMetrics () {
@@ -5,14 +5,15 @@ import {
5
5
  ensureLoggableError
6
6
  } from '@platformatic/foundation'
7
7
  import { ITC } from '@platformatic/itc/lib/index.js'
8
- import { client, collectMetrics } from '@platformatic/metrics'
8
+ import { clearRegistry, client, collectThreadMetrics } from '@platformatic/metrics'
9
9
  import diagnosticChannel, { tracingChannel } from 'node:diagnostics_channel'
10
10
  import { EventEmitter, once } from 'node:events'
11
11
  import { readFile } from 'node:fs/promises'
12
12
  import { ServerResponse } from 'node:http'
13
13
  import { register } from 'node:module'
14
14
  import { hostname, platform, tmpdir } from 'node:os'
15
- import { basename, resolve } from 'node:path'
15
+ import { basename, join, resolve } from 'node:path'
16
+ import { fileURLToPath } from 'node:url'
16
17
  import pino from 'pino'
17
18
  import { Agent, Pool, setGlobalDispatcher } from 'undici'
18
19
  import { WebSocket } from 'ws'
@@ -84,6 +85,9 @@ export class ChildProcess extends ITC {
84
85
  collectMetrics: (...args) => {
85
86
  return this.#collectMetrics(...args)
86
87
  },
88
+ updateMetricsConfig: (...args) => {
89
+ return this.#updateMetricsConfig(...args)
90
+ },
87
91
  getMetrics: (...args) => {
88
92
  return this.#getMetrics(...args)
89
93
  },
@@ -217,10 +221,23 @@ export class ChildProcess extends ITC {
217
221
  }
218
222
 
219
223
  async #collectMetrics ({ applicationId, workerId, metricsConfig }) {
220
- await collectMetrics(applicationId, workerId, metricsConfig, this.#metricsRegistry)
224
+ // Use thread-specific metrics collection - process-level metrics are collected
225
+ // by the main runtime thread and duplicated with worker labels
226
+ await collectThreadMetrics(applicationId, workerId, metricsConfig, this.#metricsRegistry)
221
227
  this.#setHttpCacheMetrics()
222
228
  }
223
229
 
230
+ async #updateMetricsConfig ({ applicationId, workerId, metricsConfig }) {
231
+ clearRegistry(this.#metricsRegistry)
232
+
233
+ if (metricsConfig.enabled !== false) {
234
+ // Use thread-specific metrics collection - process-level metrics are collected
235
+ // by the main runtime thread and duplicated with worker labels
236
+ await collectThreadMetrics(applicationId, workerId, metricsConfig, this.#metricsRegistry)
237
+ this.#setHttpCacheMetrics()
238
+ }
239
+ }
240
+
224
241
  #setHttpCacheMetrics () {
225
242
  const { client, registry } = globalThis.platformatic.prometheus
226
243
 
@@ -491,12 +508,60 @@ function stripBasePath (basePath) {
491
508
  }
492
509
  }
493
510
 
511
+ // Enable compile cache if configured (Node.js 22.1.0+)
512
+ async function setupCompileCache (contextData) {
513
+ const config = contextData?.compileCache
514
+
515
+ // Normalize boolean shorthand
516
+ const normalizeConfig = cfg => {
517
+ if (cfg === true) return { enabled: true }
518
+ if (cfg === false) return { enabled: false }
519
+ return cfg
520
+ }
521
+
522
+ const normalizedConfig = normalizeConfig(config)
523
+ if (!normalizedConfig?.enabled) {
524
+ return
525
+ }
526
+
527
+ // Check if API is available (Node.js 22.1.0+)
528
+ let moduleApi
529
+ try {
530
+ moduleApi = await import('node:module')
531
+ if (typeof moduleApi.enableCompileCache !== 'function') {
532
+ return
533
+ }
534
+ } catch {
535
+ return
536
+ }
537
+
538
+ // Use root from context data (capability's this.root as URL)
539
+ const root = contextData?.root ? fileURLToPath(contextData.root) : null
540
+ if (!root) {
541
+ return
542
+ }
543
+
544
+ const cacheDir =
545
+ typeof normalizedConfig === 'object' && normalizedConfig.directory
546
+ ? normalizedConfig.directory
547
+ : join(root, '.plt', 'compile-cache')
548
+
549
+ try {
550
+ moduleApi.enableCompileCache(cacheDir)
551
+ } catch {
552
+ // Silently ignore - cache is optional optimization
553
+ }
554
+ }
555
+
494
556
  async function main () {
495
557
  const executable = basename(process.argv[1] ?? '')
496
558
 
497
559
  const dataPath = resolve(tmpdir(), 'platformatic', 'runtimes', `${process.env.PLT_MANAGER_ID}.json`)
498
560
  const { data, loader, scripts } = JSON.parse(await readFile(dataPath))
499
561
 
562
+ // Enable compile cache early before loading user modules
563
+ await setupCompileCache(data)
564
+
500
565
  globalThis.platformatic = Object.assign(globalThis.platformatic ?? {}, data)
501
566
  globalThis.platformatic.events = new ForwardingEventEmitter()
502
567
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@platformatic/basic",
3
- "version": "3.29.1",
3
+ "version": "3.31.0",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -25,16 +25,16 @@
25
25
  "split2": "^4.2.0",
26
26
  "undici": "^7.0.0",
27
27
  "ws": "^8.18.0",
28
- "@platformatic/foundation": "3.29.1",
29
- "@platformatic/itc": "3.29.1",
30
- "@platformatic/telemetry": "3.29.1",
31
- "@platformatic/metrics": "3.29.1"
28
+ "@platformatic/foundation": "3.31.0",
29
+ "@platformatic/itc": "3.31.0",
30
+ "@platformatic/metrics": "3.31.0",
31
+ "@platformatic/telemetry": "3.31.0"
32
32
  },
33
33
  "devDependencies": {
34
34
  "cleaner-spec-reporter": "^0.5.0",
35
35
  "eslint": "9",
36
36
  "express": "^4.19.2",
37
- "fastify": "^5.0.0",
37
+ "fastify": "^5.7.0",
38
38
  "get-port": "^7.1.0",
39
39
  "json-schema-to-typescript": "^15.0.0",
40
40
  "neostandard": "^0.12.0",
package/schema.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "$id": "https://schemas.platformatic.dev/@platformatic/basic/3.29.1.json",
2
+ "$id": "https://schemas.platformatic.dev/@platformatic/basic/3.31.0.json",
3
3
  "$schema": "http://json-schema.org/draft-07/schema#",
4
4
  "title": "Platformatic Basic Config",
5
5
  "type": "object",
@@ -336,6 +336,28 @@
336
336
  }
337
337
  }
338
338
  }
339
+ },
340
+ "compileCache": {
341
+ "anyOf": [
342
+ {
343
+ "type": "boolean"
344
+ },
345
+ {
346
+ "type": "object",
347
+ "properties": {
348
+ "enabled": {
349
+ "type": "boolean",
350
+ "default": true,
351
+ "description": "Enable Node.js module compile cache for faster startup"
352
+ },
353
+ "directory": {
354
+ "type": "string",
355
+ "description": "Directory to store compile cache. Defaults to .plt/compile-cache in app root"
356
+ }
357
+ },
358
+ "additionalProperties": false
359
+ }
360
+ ]
339
361
  }
340
362
  }
341
363
  }
@@ -415,7 +437,6 @@
415
437
  "properties": {
416
438
  "level": {
417
439
  "type": "string",
418
- "default": "info",
419
440
  "oneOf": [
420
441
  {
421
442
  "enum": [
@@ -558,9 +579,6 @@
558
579
  "additionalProperties": true
559
580
  }
560
581
  },
561
- "required": [
562
- "level"
563
- ],
564
582
  "default": {},
565
583
  "additionalProperties": true
566
584
  },
@@ -1602,6 +1620,28 @@
1602
1620
  ],
1603
1621
  "additionalProperties": false
1604
1622
  },
1623
+ "compileCache": {
1624
+ "anyOf": [
1625
+ {
1626
+ "type": "boolean"
1627
+ },
1628
+ {
1629
+ "type": "object",
1630
+ "properties": {
1631
+ "enabled": {
1632
+ "type": "boolean",
1633
+ "default": true,
1634
+ "description": "Enable Node.js module compile cache for faster startup"
1635
+ },
1636
+ "directory": {
1637
+ "type": "string",
1638
+ "description": "Directory to store compile cache. Defaults to .plt/compile-cache in app root"
1639
+ }
1640
+ },
1641
+ "additionalProperties": false
1642
+ }
1643
+ ]
1644
+ },
1605
1645
  "application": {
1606
1646
  "type": "object",
1607
1647
  "properties": {
@@ -1866,6 +1906,28 @@
1866
1906
  }
1867
1907
  }
1868
1908
  }
1909
+ },
1910
+ "compileCache": {
1911
+ "anyOf": [
1912
+ {
1913
+ "type": "boolean"
1914
+ },
1915
+ {
1916
+ "type": "object",
1917
+ "properties": {
1918
+ "enabled": {
1919
+ "type": "boolean",
1920
+ "default": true,
1921
+ "description": "Enable Node.js module compile cache for faster startup"
1922
+ },
1923
+ "directory": {
1924
+ "type": "string",
1925
+ "description": "Directory to store compile cache. Defaults to .plt/compile-cache in app root"
1926
+ }
1927
+ },
1928
+ "additionalProperties": false
1929
+ }
1930
+ ]
1869
1931
  }
1870
1932
  },
1871
1933
  "additionalProperties": false