Finding #14 of the 2026-08 architecture review. Filed for completeness — low priority, and quite possibly wontfix.
Observation
OperationQueue is an array with push / shift (src/internal/OperationQueue.ts:26). Array.prototype.shift() reindexes the backing store, so each dequeue is O(n) in queue depth and a full drain is O(n²).
Why it almost certainly doesn't matter
Queues here hold pending top-level operations on a single machine, drained one at a time with real async work (conditions, observers, mutex round-trips) between them. At the depths any realistic workload produces — single digits to low hundreds — the reindex cost is invisible next to a single await. V8 also optimizes shift on small arrays well.
The only reason it is recorded at all: maxQueueLength defaults to Infinity, so nothing structurally bounds depth. A pathological producer (an event source enqueueing far faster than the machine drains, with no back-pressure configured) could reach a depth where this shows up — but such a system has a bigger problem than the queue implementation, and the fix for it is setting maxQueueLength.
If it is ever worth doing
Replace shift() with a head index and periodic compaction, or a ring buffer. It is ~10 lines behind an already-encapsulated interface (enqueue / dequeue / isEmpty / size), fully covered by existing tests, and needs no API change.
Suggested trigger: do this only if a profile on a real workload attributes measurable time to it. Otherwise close as wontfix — the current implementation is the simplest thing that works, and that has value too.
Finding #14 of the 2026-08 architecture review. Filed for completeness — low priority, and quite possibly wontfix.
Observation
OperationQueueis an array withpush/shift(src/internal/OperationQueue.ts:26).Array.prototype.shift()reindexes the backing store, so each dequeue is O(n) in queue depth and a full drain is O(n²).Why it almost certainly doesn't matter
Queues here hold pending top-level operations on a single machine, drained one at a time with real async work (conditions, observers, mutex round-trips) between them. At the depths any realistic workload produces — single digits to low hundreds — the reindex cost is invisible next to a single
await. V8 also optimizesshifton small arrays well.The only reason it is recorded at all:
maxQueueLengthdefaults toInfinity, so nothing structurally bounds depth. A pathological producer (an event source enqueueing far faster than the machine drains, with no back-pressure configured) could reach a depth where this shows up — but such a system has a bigger problem than the queue implementation, and the fix for it is settingmaxQueueLength.If it is ever worth doing
Replace
shift()with a head index and periodic compaction, or a ring buffer. It is ~10 lines behind an already-encapsulated interface (enqueue/dequeue/isEmpty/size), fully covered by existing tests, and needs no API change.Suggested trigger: do this only if a profile on a real workload attributes measurable time to it. Otherwise close as wontfix — the current implementation is the simplest thing that works, and that has value too.