feat(gateway): support per-channel and per-session queue policy overrides
This commit is contained in:
@@ -47,7 +47,8 @@ export class LaneQueue {
|
||||
* Returns a promise that resolves with the work's return value
|
||||
* once it has been executed (which may be immediately if the lane is idle).
|
||||
*/
|
||||
async enqueue<T>(laneId: string, work: () => Promise<T>): Promise<T> {
|
||||
async enqueue<T>(laneId: string, work: () => Promise<T>, policy?: Partial<LaneQueueConfig>): Promise<T> {
|
||||
const effective = this.resolvePolicy(policy);
|
||||
let lane = this.lanes.get(laneId);
|
||||
if (!lane) {
|
||||
lane = { active: false, queue: [] };
|
||||
@@ -65,12 +66,12 @@ export class LaneQueue {
|
||||
}
|
||||
}
|
||||
|
||||
if (this.config.mode === 'steer' || this.config.mode === 'interrupt') {
|
||||
if (effective.mode === 'steer' || effective.mode === 'interrupt') {
|
||||
this.rejectPending(lane, 'Superseded by newer request');
|
||||
}
|
||||
|
||||
if (lane.queue.length >= this.config.cap) {
|
||||
if (this.config.overflow === 'drop_new') {
|
||||
if (lane.queue.length >= effective.cap) {
|
||||
if (effective.overflow === 'drop_new') {
|
||||
return Promise.reject(new Error('Lane queue full (drop_new)'));
|
||||
}
|
||||
// drop_old
|
||||
@@ -131,6 +132,14 @@ export class LaneQueue {
|
||||
}
|
||||
}
|
||||
|
||||
private resolvePolicy(policy?: Partial<LaneQueueConfig>): LaneQueueConfig {
|
||||
return {
|
||||
mode: policy?.mode ?? this.config.mode,
|
||||
cap: Math.max(1, policy?.cap ?? this.config.cap),
|
||||
overflow: policy?.overflow ?? this.config.overflow,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the next queued entry for a lane (called after current work finishes).
|
||||
* Runs asynchronously so the caller's finally block completes first.
|
||||
|
||||
Reference in New Issue
Block a user