first commit
This commit is contained in:
58
docs/api-stack/api/api-ws-bun/src/limits/tenant-cap.md
Normal file
58
docs/api-stack/api/api-ws-bun/src/limits/tenant-cap.md
Normal file
@@ -0,0 +1,58 @@
|
||||
# `limits`
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
Provides the per-tenant connection-count enforcement function that the handshake pipeline calls before admitting a new connection. The cap defends every host process against a single tenant exhausting socket capacity — a noisy-neighbour mitigation explicitly called out in design §11.4 (default `maxConnectionsPerTenant=1000`).
|
||||
|
||||
Enforcement is a function rather than a class because the only state needed is the registry itself; threading another stateful module through the handshake path would obscure the actual policy decision.
|
||||
|
||||
## Features
|
||||
|
||||
- O(1) cap check — leans on `registry.countByTenant` which is index-backed.
|
||||
- Throws `WS_BUN.TENANT_CAP_EXCEEDED` with the offending tenant id + configured cap in the message for debuggable telemetry.
|
||||
- Read-only — does not mutate the registry, so the handshake path can run additional checks after the cap test without rollback.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { enforceTenantCap, BunConnectionRegistry } from "@suaveplan/api-ws-bun";
|
||||
|
||||
const registry = new BunConnectionRegistry();
|
||||
enforceTenantCap(registry, tenantId, 1000); // throws if >= 1000.
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
```ts
|
||||
import {
|
||||
enforceTenantCap,
|
||||
BunConnectionRegistry,
|
||||
WS_BUN_CODES,
|
||||
} from "@suaveplan/api-ws-bun";
|
||||
|
||||
function tryAccept(reg: BunConnectionRegistry, tenant, cap) {
|
||||
try {
|
||||
enforceTenantCap(reg, tenant, cap);
|
||||
return { accepted: true as const };
|
||||
} catch (err) {
|
||||
if ((err as { code?: string }).code === WS_BUN_CODES.TENANT_CAP_EXCEEDED) {
|
||||
return { accepted: false as const, httpStatus: 429 };
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `enforceTenantCap(registry, tenant, cap): void` — throws on cap breach; otherwise no-op.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The check uses `>=` rather than `>` so a cap of 1000 admits exactly 1000 concurrent connections; the 1001st gets the 429. This matches the spec scenario verbatim and avoids the off-by-one trap of "999 admitted, 1000 rejected".
|
||||
|
||||
The implementation does not reserve a registry slot before the cap test. The window between the check and `registry.add(conn)` is bounded by a synchronous function call in the engine, so racing two handshakes through that microsecond gap would only be possible if Bun.serve fired two upgrade callbacks on the same JavaScript turn — which it does not. If a future engine extends the gap, this function should be replaced with an atomic `reserveSlot` / `releaseSlot` pair.
|
||||
Reference in New Issue
Block a user