Skip to content

Unbounded: core/src/utils/throttler.ts — queue grows without max depth #329

@realfishsam

Description

@realfishsam

Location

core/src/utils/throttler.ts:23

Code

async throttle(cost: number = 1): Promise<void> {
    return new Promise<void>((resolve) => {
        this.queue.push({ resolve, cost }); // no depth check
        if (!this.running) {
            this.running = true;
            this.loop();
        }
    });
}

Growth Pattern

Every HTTP request made through BaseExchange flows through this throttler (BaseExchange.ts:436). When requests arrive faster than the configured refillRate allows, they are enqueued with no upper bound. Each queued item holds a live Promise resolver closure (~800 bytes of V8 heap per entry). Under a thundering-herd scenario — e.g., fetchMarkets() called across many exchanges simultaneously, or a client that fires hundreds of watchOrderBook loops — the queue inflates without any backpressure signal to the caller.

The default rateLimit is 1000 ms (1 req/sec). At 500 concurrent callers each making one HTTP call, 499 queue up immediately and stay queued. There is no maximum queue depth, no rejection, and no timeout on queued items.

OOM Estimate

  • Queue item: ~64 bytes (object with two pointers) + ~800 bytes Promise closure = ~864 bytes/item
  • At 10,000 queued items: ~8.6 MB
  • Under sustained burst (100 req/s into a 1 req/s throttle): queue grows at 99 items/sec
  • After 10 minutes: ~59,400 items ≈ 51 MB of live closures, none collectable until resolved
  • Servers with 512 MB heap running several parallel exchange clients could OOM in under 1 hour

Suggested Fix

Add a maxQueueDepth constructor option (e.g., default 512). In throttle(), if this.queue.length >= maxQueueDepth, reject immediately with a RateLimitExceeded error rather than enqueuing.


Found by automated unbounded operations audit

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions