From 0e60c6a892f7b5979d7e91c1e6bbaf09c7703b0c Mon Sep 17 00:00:00 2001 From: densetsuuu Date: Sun, 1 Feb 2026 13:22:10 +0100 Subject: [PATCH] feat: add tracing channels support for preload files --- src/managers/preloads.ts | 11 ++++++- src/tracing_channels.ts | 23 ++++++++++++++- tests/application/preloads.spec.ts | 47 ++++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+), 2 deletions(-) diff --git a/src/managers/preloads.ts b/src/managers/preloads.ts index 1910af1..517dec4 100644 --- a/src/managers/preloads.ts +++ b/src/managers/preloads.ts @@ -9,6 +9,7 @@ import debug from '../debug.ts' import type { AppEnvironments, PreloadNode } from '../types.ts' +import { preloadImport } from '../tracing_channels.ts' /** * The PreloadsManager class is used to resolve and import preload modules. @@ -110,7 +111,15 @@ export class PreloadsManager { const preloads = this.#list.filter((preload) => this.#filterByEnvironment(preload)) debug('preloading modules %O', preloads) - await Promise.all(preloads.map((preload) => preload.file())) + await Promise.all( + preloads.map((preload) => + preloadImport.tracePromise( + preload.file as () => Promise, + preloadImport.hasSubscribers ? { file: preload.file } : undefined, + preload + ) + ) + ) this.#list = [] } diff --git a/src/tracing_channels.ts b/src/tracing_channels.ts index da0af7d..8a8e01e 100644 --- a/src/tracing_channels.ts +++ b/src/tracing_channels.ts @@ -8,7 +8,7 @@ */ import diagnostics_channel from 'node:diagnostics_channel' -import { type ContainerProviderContract } from './types.ts' +import { type ContainerProviderContract, type PreloadNode } from './types.ts' /** * Tracing channel for service provider register lifecycle hook. @@ -115,3 +115,24 @@ export const providerShutdown = diagnostics_channel.tracingChannel< 'adonisjs.provider.shutdown', { provider: ContainerProviderContract } >('adonisjs.provider.shutdown') + +/** + * Tracing channel for preload file import. + * This channel traces when a preload module is imported during + * the application start phase. + * + * @example + * // Monitor preload imports + * preloadImport.subscribe({ + * asyncStart(data) { + * console.log('Importing preload:', data.file.toString()) + * }, + * asyncEnd(data) { + * console.log('Preload imported:', data.file.toString()) + * } + * }) + */ +export const preloadImport = diagnostics_channel.tracingChannel< + 'adonisjs.preload.import', + { file: PreloadNode['file'] } +>('adonisjs.preload.import') diff --git a/tests/application/preloads.spec.ts b/tests/application/preloads.spec.ts index 61f31b0..8e22b9d 100644 --- a/tests/application/preloads.spec.ts +++ b/tests/application/preloads.spec.ts @@ -12,6 +12,7 @@ import { test } from '@japa/runner' import { fileURLToPath } from 'node:url' import { outputFile, remove } from 'fs-extra' import { Application } from '../../src/application.ts' +import { preloadImport } from '../../src/tracing_channels.ts' const BASE_URL = new URL('./app/', import.meta.url) const BASE_PATH = fileURLToPath(BASE_URL) @@ -223,4 +224,50 @@ test.group('Application | preloads', (group) => { assert.equal(process.env.HAS_ROUTES, 'true') }) + + test('trace preload imports', async ({ assert, cleanup }) => { + cleanup(() => { + delete process.env.HAS_ROUTES + }) + + await outputFile( + join(BASE_PATH, './routes.ts'), + ` + process.env.HAS_ROUTES = 'true' + ` + ) + + const app = new Application(BASE_URL, { + environment: 'web', + }) + + app.rcContents({ + preloads: [ + { + file: () => import(new URL('./routes.js?v=30', BASE_URL).href), + environment: ['web'], + optional: false, + }, + ], + }) + + const spans: any[] = [] + preloadImport.subscribe({ + asyncStart(message: any) { + spans.push({ file: message.file, startTime: process.hrtime() }) + }, + asyncEnd() { + const span = spans[spans.length - 1] + span.duration = process.hrtime(span.startTime) + }, + } as any) + + await app.init() + await app.boot() + await app.start(() => {}) + + assert.lengthOf(spans, 1) + assert.properties(spans[0], ['file', 'startTime', 'duration']) + assert.equal(process.env.HAS_ROUTES, 'true') + }) })