first commit
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
# `backpressure.ts` — bounded-queue accounting for the event-bus service
|
||||
|
||||
## Purpose
|
||||
|
||||
Wraps `@suaveplan/events`' `BoundedQueue` with a small adapter that
|
||||
treats the queue as a pure accounting primitive: a publish reserves a
|
||||
slot, drains it immediately, and the adapter reports whether the
|
||||
publish counts as "dropped" under the configured policy. Keeping this
|
||||
logic in a focused module lets `event-bus-service.ts` stay under the
|
||||
300-line file budget and makes the back-pressure semantics testable in
|
||||
isolation.
|
||||
|
||||
## Features
|
||||
|
||||
- Constructs a `BoundedQueue<unknown>` plus a public `capacity` /
|
||||
`policy` view (the queue itself keeps these private).
|
||||
- `tryEnqueue` translates `EVENTS.QUEUE.OVERFLOW` into
|
||||
`EventBusError(EVENT_BUS.BACKPRESSURE_DROPPED)`.
|
||||
- Reports `dropped: true` for `drop-oldest` / `drop-newest` policies
|
||||
when the queue was at capacity before enqueue.
|
||||
- Forwards `AbortSignal` through to the underlying queue.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import {
|
||||
createBackpressureState,
|
||||
tryEnqueue,
|
||||
} from "@suaveplan/api-plugin-event-bus/services/event-bus-service";
|
||||
|
||||
const state = createBackpressureState({
|
||||
capacity: 8,
|
||||
policy: "drop-oldest",
|
||||
});
|
||||
const outcome = await tryEnqueue(state, { hello: "world" }, undefined);
|
||||
console.log(outcome.dropped);
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
```ts
|
||||
import {
|
||||
createBackpressureState,
|
||||
tryEnqueue,
|
||||
} from "@suaveplan/api-plugin-event-bus/services/event-bus-service";
|
||||
|
||||
const state = createBackpressureState({ capacity: 1, policy: "throw" });
|
||||
await tryEnqueue(state, "a", undefined);
|
||||
try {
|
||||
await tryEnqueue(state, "b", undefined);
|
||||
} catch (err) {
|
||||
// EventBusError(EVENT_BUS.BACKPRESSURE_DROPPED)
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `createBackpressureState(opts: BackpressureOptions): BackpressureState`
|
||||
|
||||
Build the queue + companion accounting struct used by the service.
|
||||
|
||||
### `tryEnqueue(state, payload, signal): Promise<EnqueueOutcome>`
|
||||
|
||||
Reserves a slot, drains it, and returns `{ dropped }`. Throws
|
||||
`EventBusError(EVENT_BUS.BACKPRESSURE_DROPPED)` under `policy: "throw"`
|
||||
when the queue is full.
|
||||
|
||||
### `interface BackpressureState`
|
||||
|
||||
`{ queue: BoundedQueue<unknown>; capacity: number; policy: QueuePolicy }`.
|
||||
|
||||
### `interface EnqueueOutcome`
|
||||
|
||||
`{ dropped: boolean }`.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
- We drain the queue immediately because we use it only for
|
||||
accounting — the actual dispatch is owned by `EventBus.emitAsync`.
|
||||
If the bus ever grows a queue-driven dispatch model, the `dequeue`
|
||||
call disappears and the queue starts carrying the payload.
|
||||
- "would-overflow" is computed **before** `enqueue` because under
|
||||
`drop-oldest` the queue swallows the oldest item synchronously and
|
||||
the post-enqueue size would not reveal the drop.
|
||||
- The thrown `EventBusError` carries `context.statusCode: 503` so the
|
||||
HTTP layer translates back-pressure rejections to "Service
|
||||
Unavailable" automatically.
|
||||
Reference in New Issue
Block a user