Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion src/managers/preloads.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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<void>,
preloadImport.hasSubscribers ? { file: preload.file } : undefined,
preload
)
)
)

this.#list = []
}
Expand Down
23 changes: 22 additions & 1 deletion src/tracing_channels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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')
47 changes: 47 additions & 0 deletions tests/application/preloads.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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')
})
})