UNPKG

@stacksjs/rpx

Version:

A modern and smart reverse proxy.

83 lines (82 loc) 3.34 kB
/** * Forward a request through the pooled transport and return the upstream * {@link Response}. Throws {@link FALLBACK} for cases it intentionally declines * (large/streaming uploads, `Expect`, upgrades) so the caller can use `fetch()`. */ export declare function proxyViaPool(reqOpts: PoolRequest): Promise<Response>; /** Sentinel thrown when the pooled path declines a request; caller uses fetch(). */ export declare const FALLBACK: unique symbol; /** Thrown when the upstream stalls past the configured timeout; caller maps to 504. */ export declare const TIMEOUT: unique symbol; /** * Thrown when every connection to an upstream is busy and the wait for a free * slot exceeded {@link queueWaitMs}, or the waiter queue is already at its cap. * The caller maps it to a 503. This is the backstop that keeps a saturated or * stalled upstream from making the *listener* appear wedged: instead of parking * a request forever with no response (the production incident), rpx fails it * fast and loud so the listener keeps answering every other request. */ export declare const POOL_BUSY: unique symbol; export declare interface PoolRequest { hostPort: string method: string path: string reqHeaders: Headers forwardedHost: string originOverride?: string body: ReadableStream<Uint8Array> | null maxPerHost?: number } /** * One pooled upstream socket. A connection serves a single request at a time * (HTTP/1.1, no pipelining); it is checked out of the pool for the duration of a * request and returned once the response body is fully read. */ declare class Conn { socket: import('bun').Socket<undefined> | null; buf: Uint8Array; len: unknown; fresh: boolean; timedOut: boolean; idleSince: number; bodyQueue: Uint8Array[] | null; bodyRemaining: number; queuedBytes: number; streamingBody: boolean; lastActivityAt: number; drainWaiter: (() => void) | null; writeAll(bytes: Uint8Array): Promise<void>; wakeDrain(): void; push(chunk: Uint8Array): void; resumeIfDrained(): void; clearStreaming(): void; markClosed(): void; markTimedOut(): void; waitForData(seen: number): Promise<void>; waitForBody(): Promise<void>; compact(): void; destroy(): void; } /** * A bounded keepalive connection pool for a single upstream `host:port`. * * It caps the *total* number of open connections at `maxTotal` and **queues** * requests that arrive while every connection is busy, handing each released * connection straight to the next waiter. Connections are only ever closed on * error or after sitting idle past the timeout — never on the hot release path. * * Bounding the total (rather than just the idle set) is what makes it * collapse-safe: a fixed set of connections is reused indefinitely, so there is * no per-request churn to pile sockets into TIME_WAIT and exhaust ephemeral * ports under a flood. The price is that at concurrency above `maxTotal`, * throughput is bounded by the pool size instead of growing unbounded — exactly * the trade nginx makes, and the reason it stays up under load. */ declare class UpstreamPool { constructor(host: string, port: number, maxTotal: number, key?: string); dial(): Promise<Conn>; acquireIdleSync(): Conn | null; acquireOrDial(): Promise<Conn>; release(conn: Conn): void; destroy(conn: Conn): void; }