first commit
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
# `backpressure`
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
Enforces the per-connection send-queue cap described in design §11.4. Each connection owns one `BackpressureGuard` instance; every outbound message increments the guard's depth, and the guard fires the eviction callback (and throws `WS_BUN.BACKPRESSURE_EVICTED`) the first time the depth exceeds `maxQueuedMessages`.
|
||||
|
||||
The guard reuses `evaluateBackpressure` from `@suaveplan/api-ws` so the eviction threshold stays identical across every engine that implements the contract — only the storage / wire layer differs.
|
||||
|
||||
## Features
|
||||
|
||||
- Constant-time `enqueue()` and `release(n)` operations.
|
||||
- Idempotent eviction — re-`enqueue` after eviction throws the same `WS_BUN.BACKPRESSURE_EVICTED` code rather than firing the callback twice.
|
||||
- Exposes `queued` depth and `isEvicted` for instruments and assertions.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { BackpressureGuard } from "@suaveplan/api-ws-bun";
|
||||
|
||||
const guard = new BackpressureGuard("c1", 4, (id) => console.log(`evict ${id}`));
|
||||
for (let i = 0; i < 4; i++) guard.enqueue();
|
||||
console.log(guard.queued); // 4
|
||||
guard.release(2);
|
||||
console.log(guard.queued); // 2
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
```ts
|
||||
import { BackpressureGuard, WsBunError } from "@suaveplan/api-ws-bun";
|
||||
|
||||
const guard = new BackpressureGuard("c2", 2, () => undefined);
|
||||
try {
|
||||
for (let i = 0; i < 5; i++) guard.enqueue();
|
||||
} catch (err) {
|
||||
if (err instanceof WsBunError) {
|
||||
// err.wsBunCode === "WS_BUN.BACKPRESSURE_EVICTED"
|
||||
// The engine maps this onto a close frame with the same reason.
|
||||
}
|
||||
}
|
||||
console.log(guard.isEvicted); // true
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `new BackpressureGuard(connectionId, maxQueuedMessages, onEvict)` — constructor.
|
||||
- `guard.enqueue(): "accept"` — accounts for one outbound message; throws on overflow.
|
||||
- `guard.release(n?: number): void` — frees up `n` slots after the socket flushed; defaults to `1`.
|
||||
- `guard.queued: number` — current queue depth.
|
||||
- `guard.isEvicted: boolean` — true once eviction has fired.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The guard intentionally throws inside `enqueue()` rather than returning `"evict"` to the caller. This lets the engine treat backpressure overflow as a thrown error that propagates through the OTel span automatically, keeping every overflow path symmetrical with the other `WS_BUN.*` codes.
|
||||
|
||||
`release` clamps the depth at zero so a buggy caller cannot make the guard "lend" capacity it never accounted for. The clamp is silent — overshoot is treated as ignorable bookkeeping noise.
|
||||
Reference in New Issue
Block a user