Files
skills/docs/api-stack/api/api-sse-bun/src/limits/tenant-cap.md
2026-05-29 08:20:56 +01:00

2.2 KiB

tenant-cap

(no submodules)

Purpose

The tenant-cap module owns the per-tenant SSE connection counter the engine consults during handshake. A tenant that has already reached maxConnectionsPerTenant open connections receives 429 Too Many Requests with SSE_BUN.TENANT_CAP_EXCEEDED — the engine never opens the long-lived stream, so the per-tenant ceiling is enforced exactly at the handshake boundary and never as a mid-stream race.

Features

  • O(1) tryAcquire / release keyed by TenantId.
  • count(tenantId) exposed so OTel gauges can sample without exposing the internal map.
  • total aggregate count for global capacity dashboards.
  • Tight error context: tenantId, limit, current attached to every thrown SseBunError so operators do not need to grep request logs.
  • Idempotent release — releasing an unknown tenant does nothing.

Usage: Basic

import { createTenantConnectionCap } from "@suaveplan/api-sse-bun";

const cap = createTenantConnectionCap(1000);
cap.tryAcquire("acme" as never);
console.log(cap.count("acme" as never)); // 1
cap.release("acme" as never);

Usage: Advanced

import {
    createTenantConnectionCap,
    SSE_BUN_CODES,
    SseBunError,
} from "@suaveplan/api-sse-bun";

const cap = createTenantConnectionCap(2);
const tenant = "acme" as never;
cap.tryAcquire(tenant);
cap.tryAcquire(tenant);
try {
    cap.tryAcquire(tenant);
} catch (err) {
    if (
        err instanceof SseBunError &&
        err.code === SSE_BUN_CODES.TENANT_CAP_EXCEEDED
    ) {
        // return 429 ...
    }
}

API Reference

  • interface TenantConnectionCap — tryAcquire(tenantId), release(tenantId), count(tenantId), total.
  • function createTenantConnectionCap(max): TenantConnectionCap.

Implementation Notes

The cap uses a Map<TenantId, number> keyed by the branded tenant id; the brand prevents an unsanitised header value from accidentally being treated as a tenant key. release decrements when the count is > 1 and deletes the entry on the last release so the map's footprint matches the live connection set. total is a running counter rather than a derived sum so reading it from the OTel callback is O(1).