From 08e13f5f66bf38bd8a4571b6ab433179680e4703 Mon Sep 17 00:00:00 2001 From: Dinh Le Date: Tue, 6 Oct 2026 11:06:39 +0700 Subject: [PATCH] chore: serve static file benchmarks from memory The static file handler benches read real files, so CodSpeed's single measured call hopped through the libuv thread pool and event loop and picked up unrelated callbacks, flipping results by 12% or more on PRs that never touched the plugin. Back the plugin with an in-memory fs and stop importing the shared payloads, so every measured call is the same microtask chain. --- benches/static-file-handler.bench.ts | 66 +++++++++++++++++++++++++--- 1 file changed, 59 insertions(+), 7 deletions(-) diff --git a/benches/static-file-handler.bench.ts b/benches/static-file-handler.bench.ts index 9d4d900d1..f6645195f 100644 --- a/benches/static-file-handler.bench.ts +++ b/benches/static-file-handler.bench.ts @@ -1,18 +1,62 @@ import type { StandardLazyRequest } from '@standard-server/core' +import type { Stats } from 'node:fs' import { Buffer } from 'node:buffer' -import { mkdirSync, mkdtempSync, writeFileSync } from 'node:fs' -import { tmpdir } from 'node:os' import path from 'node:path' +import { Readable } from 'node:stream' import { StaticFileHandlerPlugin } from '@orpc/node' import { RPCHandlerCodec, StandardHandler } from '@orpc/server/standard' import { bench } from 'vitest' -import { drainBody } from './__shared__/payloads' -const rootDir = mkdtempSync(path.join(tmpdir(), 'orpc-static-file-bench-')) +/** + * CodSpeed measures a single call, so files are served from memory: real fs calls hop through the + * libuv thread pool and the event loop, which lets thread scheduling and unrelated callbacks + * (like vitest's worker IPC) land in the measurement and flip results between runs. + * The shared payloads are not imported either, since building them changes how much V8 compilation + * lands in the first measured call. + */ +vi.mock('node:fs', async importOriginal => ({ ...await importOriginal(), createReadStream })) +vi.mock('node:fs/promises', async importOriginal => ({ ...await importOriginal(), stat, realpath })) -writeFileSync(path.join(rootDir, 'file.txt'), Buffer.alloc(10 * 1024, 'a')) -mkdirSync(path.join(rootDir, 'deeply', 'nested', 'dir'), { recursive: true }) -writeFileSync(path.join(rootDir, 'deeply', 'nested', 'dir', 'file.txt'), Buffer.alloc(10 * 1024, 'a')) +const rootDir = path.resolve('/static') +const mtime = new Date('2024-01-01T00:00:00.000Z') + +const files = new Map([ + [path.join(rootDir, 'file.txt'), Buffer.alloc(10 * 1024, 'a')], + [path.join(rootDir, 'deeply', 'nested', 'dir', 'file.txt'), Buffer.alloc(10 * 1024, 'a')], +]) + +function notFound(filePath: string): Error { + return Object.assign(new Error(`ENOENT: no such file or directory, '${filePath}'`), { code: 'ENOENT' }) +} + +async function stat(filePath: string): Promise { + const content = files.get(filePath) + + if (content === undefined) { + throw notFound(filePath) + } + + return { size: content.length, mtime, isFile: () => true, isDirectory: () => false } as Stats +} + +async function realpath(filePath: string): Promise { + if (filePath !== rootDir && !files.has(filePath)) { + throw notFound(filePath) + } + + return filePath +} + +function createReadStream(filePath: string, { start = 0, end = Infinity }: { start?: number, end?: number } = {}): Readable { + const chunk = files.get(filePath)!.subarray(start, end + 1) + + return new Readable({ + read() { + this.push(chunk) + this.push(null) + }, + }) +} const handler = new StandardHandler(new RPCHandlerCodec({}, {}), { plugins: [new StaticFileHandlerPlugin({ rootDir })], @@ -27,6 +71,14 @@ function createRequest(url: `/${string}`, headers: Record = {}): } } +async function drainBody(body: unknown): Promise { + const reader = (body as ReadableStream).getReader() + + while (!(await reader.read()).done) { + // discard the chunk + } +} + const { response } = await handler.handle(createRequest('/file.txt'), { context: {} }) await drainBody(response!.body) const etag = response!.headers.etag as string