Appearance
Step-by-Step Rebuild Guide: RFC 9111 CDN Caching Proxy
This guide documents the exact dependency-ordered sequence for rebuilding 17-cdn-caching-proxy from a blank directory.
Phase 1: Ingress Listener & Stream Pipeline
- Initialize Project:bash
npm init -y npm install zod npm install -D typescript vitest tsx @types/node selfsigned - Create Ingress Listener (
src/proxy/listener.ts):- Wrap Node.js
http.createServerandhttps.createServer. - Setup SNI certificate dispatch (
src/tls/cert-watcher.ts).
- Wrap Node.js
- Key Code Implementation:typescriptExplanation: Binds client socket error listeners immediately to prevent uncaught socket hangup crashes.
// src/proxy/listener.ts:25 export function createProxyServer(handler: (req: http.IncomingMessage, res: http.ServerResponse) => void): http.Server { return http.createServer((req, res) => { req.on('error', (err) => console.error('[client-req-err]', err)); res.on('error', (err) => console.error('[client-res-err]', err)); handler(req, res); }); }
Phase 2: Canonical Cache Keys & RFC 9111 Freshness
- Canonical Cache Key Generator (
src/cache/key.ts,src/cache/key-normalize.ts):- Lowercase hostname and scheme.
- Sort URL query parameters alphabetically (
foo=1&bar=2becomesbar=2&foo=1). - Append secondary key hashes from
Varyheaders (Accept-Encoding).
- RFC 9111 Cache-Control Parser (
src/cache/cache-control.ts):- Parse
max-age,s-maxage,no-cache,no-store,stale-while-revalidate.
- Parse
Phase 3: Multi-Tier Memory & Disk Storage
- MemoryStore (
src/cache/memory-store.ts):- Allocate in-memory Buffers indexed by canonical SHA-256 keys.
- Bound by
maxTotalBytesandmaxObjectBytes.
- Eviction Policies (
src/cache/eviction/):- Implement
LruPolicyusing doubly-linked list nodes. - Add
SlruPolicy(Segmented LRU) to isolate probationary vs protected entries.
- Implement
- Key Code Implementation:typescript
// src/cache/memory-store.ts:65 public store(keyHash: string, entry: CacheEntry): boolean { if (entry.body.length > this.maxObjectBytes) return false; while (this.currentBytes + entry.body.length > this.maxTotalBytes) { const evictedKey = this.evictionPolicy.evictNext(); if (!evictedKey) break; this.delete(evictedKey); } this.entries.set(keyHash, entry); this.currentBytes += entry.body.length; return true; }
Phase 4: Request Coalescing (Thundering Herd Protection)
- In-Flight Flight Coordinator (
src/proxy/coalesce.ts):- Maintain
Map<string, InflightFlight>. - First request becomes leader; subsequent requests await stream fanout.
- Maintain
- Key Code Implementation:typescript
// src/proxy/coalesce.ts:38 public joinOrLead(keyHash: string, requestId: string): { isLeader: boolean; waitPromise?: Promise<CoalesceResult> } { const existing = this.flightMap.get(keyHash); if (existing) { const promise = new Promise<CoalesceResult>((resolve, reject) => { existing.waiters.set(requestId, { requestId, resolve, reject }); }); return { isLeader: false, waitPromise: promise }; } this.flightMap.set(keyHash, { keyHash, leaderRequestId: requestId, waiters: new Map(), createdAt: Date.now() }); return { isLeader: true }; }
Phase 5: Streaming Compression & Range Slicing
- Compression Pipeline (
src/compression/codecs.ts):- Implement on-the-fly streaming
zlib.createBrotliCompress()andzlib.createGzip(). - Add
DecompressionBombLimitertransform to prevent zip-bomb heap exhaustion.
- Implement on-the-fly streaming
- Range Parser (
src/range/parse-range.ts):- Parse
Range: bytes=start-endand slice stream directly to output206 Partial Content.
- Parse
Phase 6: Surrogate-Key Tag Purge & Audit Trail
- Inverted Index Store (
src/purge/index-store.ts):- Index entries by tag:
Map<string, Set<string>>.
- Index entries by tag:
- Tamper-Evident Audit Chain (
src/purge/audit.ts):- Hash each purge entry with
crypto.createHash('sha256')linked to the previous entry hash.
- Hash each purge entry with
Phase 7: Multi-Origin Load Balancing & Health Probes
- Origin Pools (
src/config/origins.ts):- Support weighted round-robin distribution.
- Active Health Probes (
src/health/active.ts) & Circuit Breaker (src/health/circuit-breaker.ts):- Probe endpoints every 5 seconds. Trip to Open after 3 consecutive failures.
Phase 8: Telemetry, Admin API & Next.js UI
- Prometheus Metrics (
src/observability/metrics.ts):- Expose counters, gauges, and histograms at
GET /metrics.
- Expose counters, gauges, and histograms at
- Admin Server (
src/admin/server.ts):- Run on port 9090 with Bearer token authentication and embedded SPA (
dashboard-html.ts).
- Run on port 9090 with Bearer token authentication and embedded SPA (
- Next.js Dashboard (
frontend/app/dashboard/page.tsx):- Poll telemetry API and visualize hit ratio, latency, and cache sizes via Recharts.