Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

fix: replace dedup resolver closure chain with array to prevent hangs#25

Merged
1bcMax merged 1 commit intoBlockRunAI:main from
justiniggy:fix/dedup-resolver-race-condition
Feb 14, 2026
Merged

fix: replace dedup resolver closure chain with array to prevent hangs #25
1bcMax merged 1 commit intoBlockRunAI:main from
justiniggy:fix/dedup-resolver-race-condition

Conversation

@justiniggy
Copy link
Contributor

@justiniggy justiniggy commented Feb 14, 2026

Summary

  • Replace fragile closure-chain pattern in RequestDeduplicator with a simple resolvers array
  • Fix removeInflight() silently dropping waiters — they now receive a 503 response instead of hanging forever

Problem

1. Closure chain is fragile and hard to reason about:

The old getInflight() chained each new waiter by capturing and wrapping the previous entry.resolve via closures:

const orig = entry.resolve;
entry.resolve = (result) => {
 orig(result); // call previous
 resolve(result); // resolve this waiter
};

This pattern is hard to verify for correctness and makes the code unnecessarily complex.

2. removeInflight() causes waiters to hang forever (real bug):

When the original request fails (client disconnect, timeout, error), removeInflight() was called which simply deleted the inflight entry:

removeInflight(key: string): void {
 this.inflight.delete(key); // waiters' promises never resolve!
}

Any waiters (getInflight() callers) would have promises that never resolve, causing those HTTP responses to hang indefinitely until the client times out.

Fix

  • InflightEntry now holds resolvers: Array<(result) => void> instead of a single resolve function + waiters array
  • complete() iterates all resolvers
  • removeInflight() resolves all waiters with a 503 error response so they can retry independently

Test plan

  • Verify build passes: npm run build
  • Send two identical requests concurrently → second should wait for first and get same response
  • Kill the first request mid-flight → second should get 503 (not hang forever)
  • Send request, let it complete, send same request within 30s → should get cached response

🤖 Generated with Claude Code

The previous implementation chained waiters by patching entry.resolve
via closures. This was fragile and hard to reason about.
More critically, removeInflight() (called on client disconnect or
request error) deleted the inflight entry without resolving pending
waiters — causing them to hang forever with no response.
Changes:
- Replace closure-chain pattern with a simple resolvers array
- On complete(): iterate all resolvers and resolve each one
- On removeInflight(): resolve waiters with 503 error instead of
 leaving them hanging, so clients can retry independently
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@1bcMax 1bcMax merged commit b25a348 into BlockRunAI:main Feb 14, 2026
1 check failed
1bcMax pushed a commit that referenced this pull request Feb 16, 2026
...#25)
The previous implementation chained waiters by patching entry.resolve
via closures. This was fragile and hard to reason about.
More critically, removeInflight() (called on client disconnect or
request error) deleted the inflight entry without resolving pending
waiters — causing them to hang forever with no response.
Changes:
- Replace closure-chain pattern with a simple resolvers array
- On complete(): iterate all resolvers and resolve each one
- On removeInflight(): resolve waiters with 503 error instead of
 leaving them hanging, so clients can retry independently
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

No reviews

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

AltStyle によって変換されたページ (->オリジナル) /