Skip to content

fix(rate-limit): patch Bottleneck doExpire capacity leak - #9328

Merged
diegosouzapw merged 1 commit into
diegosouzapw:release/v3.8.50from
HouMinXi:fix/bottleneck-doexpire-patch-v2
Aug 11, 2026
Merged

diegosouzapw merged 1 commit into
diegosouzapw:release/v3.8.50from
HouMinXi:fix/bottleneck-doexpire-patch-v2

Conversation

@HouMinXi

@HouMinXi HouMinXi commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Re-cut of #9151 onto the live release/v3.8.50 tip. The original branch shared
a merge-base 20 commits behind and carried a file-size-baseline.json commit
that re-encoded every non-ASCII character in the file as \uXXXX, so the diff
read as +432/-184 with the whole baseline rewritten. Same fix, no rewrite:
4 files, +248/-0.

Problem

Bottleneck v2.19.5's doExpire (Job.js:162) has a typo that compares the job ID
to the string "RUNNING" instead of checking the job's actual status. When a
job's execution time exceeds the expiration timeout, doExpire fires but fails
to advance the job from RUNNING to EXECUTING. The resulting exception is
swallowed by setTimeout, leaving the job permanently stuck in RUNNING state and
Bottleneck's internal _running counter permanently incremented -- a capacity
leak that eventually causes "all accounts inactive" even with available
reservoir.

The bug is unfixed upstream (v2.19.5 is the latest release; master still has it).

Fix

  1. Monkey-patch Bottleneck.prototype._run to correct job.doExpire before
    the expiration timeout fires. The patch uses job.id (not job.options.id)
    for status lookup, includes a _doExpirePatched guard against recursive
    wrapping, and adds optional chaining on states.next.

  2. Diagnostic fallback in withRateLimit: when a queue timeout fires and the
    limiter shows running > 0, executing = 0, reservoir > 0 (the leak pattern)
    with no recent dispatch, evict the limiter and retry.

Files changed

File Change
open-sse/services/bottleneckPatch.ts new, +81
open-sse/services/rateLimitManager.ts +24
tests/unit/bottleneck-doexpire-patch.test.ts new, +142
config/quality/file-size-baseline.json +1 (one rebaseline key)

Testing

node --import tsx/esm --test tests/unit/bottleneck-doexpire-patch.test.ts
-- 5/5 pass. npm run typecheck:core clean.

npm run check:file-size and npx eslint each report one violation on this
branch, both reproduced on an untouched release/v3.8.50 checkout
(open-sse/executors/base.ts 1623 > 1578, and the toNumber local definition
in rateLimitManager.ts), so neither is introduced here and neither is fixed
here.

@HouMinXi
HouMinXi requested a review from diegosouzapw as a code owner August 4, 2026 04:00
@HouMinXi
HouMinXi force-pushed the fix/bottleneck-doexpire-patch-v2 branch 4 times, most recently from 21717fa to 6c83d1c Compare August 10, 2026 12:17
@diegosouzapw
diegosouzapw force-pushed the fix/bottleneck-doexpire-patch-v2 branch 2 times, most recently from 3edf0aa to 0803cb1 Compare August 11, 2026 13:08
@diegosouzapw
diegosouzapw force-pushed the fix/bottleneck-doexpire-patch-v2 branch from 0803cb1 to 2badd2d Compare August 11, 2026 13:13
@diegosouzapw
diegosouzapw merged commit fb83f43 into diegosouzapw:release/v3.8.50 Aug 11, 2026
2 of 5 checks passed
fenix007 pushed a commit to fenix007/OmniRoute that referenced this pull request Aug 20, 2026
@HouMinXi
HouMinXi deleted the fix/bottleneck-doexpire-patch-v2 branch September 16, 2026 13:58
muhamadgalihsaputra pushed a commit to niyatna/NiyatnaRoute that referenced this pull request Sep 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants