@stacksjs/rpx
Version:
A modern and smart reverse proxy.
83 lines (82 loc) • 3.34 kB
TypeScript
/**
* 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;
}