Skip to content

perf(api): compile request controller resolution - #29

Merged
Upd4ting merged 1 commit into
mainfrom
perf/request-controller-resolution
Aug 19, 2026
Merged

perf(api): compile request controller resolution#29
Upd4ting merged 1 commit into
mainfrom
perf/request-controller-resolution

Conversation

@Upd4ting

@Upd4ting Upd4ting commented Aug 19, 2026

Copy link
Copy Markdown
Member

Summary

  • compile controller metadata and parameter resolver chains when routes register
  • keep controller instances and computed values request-local
  • skip Promise construction for synchronous providers and handlers while preserving concurrent async property/parameter resolution
  • add regression coverage for request isolation, in-request reuse, inheritance, computed values, parameters, and errors

Design and scope safety

The registration callback now builds immutable handler resolver plans and caches one mutable controller plan per controller class in a WeakMap. Request execution only reads those plans. It still creates a fresh controller cache on each RequestContext, and a controller enters that cache only after its computed properties resolve. No request-derived value is stored in the registration cache.

This change is limited to src/implementations/api/index.ts; middleware and router fast paths are unchanged.

Benchmark

Environment: Node 20.9.0, Linux x64, same orb and checkout, HTTP keep-alive, autocannon, 50 connections. Each scenario received a 3-second warm-up followed by five independent 5-second runs. Values below are run means; dispersion is the coefficient of variation across the five runs. Both revisions reported zero errors/timeouts/non-2xx responses.

Scenario Before req/s After req/s Change p99 before → after Dispersion before → after
GET, no computed parameters 34,667 37,443 +8.0% 2.2 → 2.0 ms 2.3% → 3.2%
Dynamic GET 30,971 35,876 +15.8% 3.0 → 2.0 ms 1.1% → 4.0%
POST / JSON body 21,179 26,662 +25.9% 4.0 → 3.2 ms 1.6% → 1.9%
Computed property 29,548 36,316 +22.9% 3.2 → 2.8 ms 2.6% → 1.5%
Four parameters 27,798 32,976 +18.6% 3.2 → 2.6 ms 1.9% → 4.2%

Server RSS after the complete sequential suite was 92,052 KiB before and 91,364 KiB after (-0.7%). This is only an indicative endpoint measurement, not an allocation profile.

Adonis and Nest/Fastify were not included: neither framework is installed in this repository, and introducing separately configured applications would make this focused before/after comparison less controlled. No cross-framework performance claim is made.

Verification

  • pnpm test: 125 passing
  • pnpm lint: passes, with the existing src/server.ts:209 accumulator-spread warning
  • pnpm run build: passes

Risks and limits

  • Resolver plans intentionally snapshot providers and modifiers at route registration. Runtime mutation of decorator metadata after registration is not supported by this optimization.
  • Async providers/modifiers still retain their Promise semantics and ordering; only fully synchronous chains use the no-Promise path.
  • The public GetControllerInstance contract remains async and falls back to one-time metadata compilation when called for a controller without a registered route.

Greptile Summary

The PR compiles controller and handler resolution metadata during route registration to reduce per-request work while preserving request-local controller instances.

  • Adds compiled parameter, computed-property, controller, and handler resolver plans.
  • Adds synchronous fast paths while retaining concurrent asynchronous resolution.
  • Adds regression coverage for request isolation, reuse, inheritance, computed values, parameters, and error propagation.

Confidence Score: 5/5

The PR appears safe to merge, with no concrete blocking or independently actionable non-blocking issue identified.

The compiled plans preserve request-local caching and parameter semantics on reachable repository paths, and sequential request dispatch prevents overlapping controller initialization within the same request.

Important Files Changed

Filename Overview
src/implementations/api/index.ts Compiles reusable resolver plans at registration and introduces synchronous execution paths without an accepted correctness defect.
src/test/controller-resolution.test.ts Adds focused HTTP-level regression coverage for controller isolation, request-local reuse, inheritance, resolver binding, and failures.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[Route registration] --> B[Compile handler plan]
  B --> C[Compile or update controller plan]
  B --> D[Compile parameter resolvers]
  E[Incoming request] --> F[Resolve request-local controller]
  C --> F
  F --> G{Controller cached?}
  G -->|Yes| H[Reuse instance]
  G -->|No| I[Create instance]
  I --> J[Resolve computed properties]
  J --> K[Cache instance in RequestContext]
  H --> L[Resolve handler parameters]
  K --> L
  D --> L
  L --> M[Invoke controller callback]
Loading

Reviews (1): Last reviewed commit: "perf(api): compile controller resolution..." | Re-trigger Greptile

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants