Skip to content

fix: add 30s timeout to SQLite semaphore to prevent deadlock hangs - #31461

Closed
HrushiYadav wants to merge 1 commit into
anomalyco:devfrom
HrushiYadav:fix/sqlite-lock-timeout
Closed

HrushiYadav wants to merge 1 commit into
anomalyco:devfrom
HrushiYadav:fix/sqlite-lock-timeout

Conversation

@HrushiYadav

Copy link
Copy Markdown

Issue for this PR

Closes #29395

Type of change

  • Bug fix

What does this PR do?

The in-process Semaphore(1) guarding the single SQLite connection in sqlite.bun.ts blocks forever when the permit can't be acquired (deadlock, re-entrant lock, or concurrent instance contention). This adds a 30-second Effect.timeoutFail to both the regular query acquirer and the transaction acquirer so the hang surfaces as a clear SqlError instead of a silent futex wait with no timeout, no error, and no progress.

How did you verify your code works?

  • Traced the full boot sequence (InstanceStore.load -> boot -> fromDirectory -> bootstrap.run) and confirmed both the acquirer and transactionAcquirer are the only JS-level serialization points for SQLite access
  • Verified Effect.timeoutFail correctly interacts with semaphore.withPermits (timeout fires interruption, permit is not acquired, no leak)
  • Verified Effect.timeoutFail works inside Effect.uninterruptibleMask + restore(...) (the restore region makes semaphore.take interruptible so the timeout signal can reach it)
  • Confirmed SqlError with classifySqliteError matches the existing error handling path

Screenshots / recordings

N/A (backend change)

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

dannyisbad added a commit to dannyisbad/opencode that referenced this pull request Jun 12, 2026
Backport of anomalyco#31461 (by @HrushiYadav). Ported timeoutFail ->
timeoutOrElse({orElse: () => Effect.fail(...)}) because [email protected] has
no timeoutFail. An indefinite semaphore wait could deadlock the whole DB layer;
now it fails with a SqlError after 30s instead of hanging.

Co-Authored-By: Claude Mythos 5 <[email protected]>
The in-process Semaphore(1) guarding the single SQLite connection has no
timeout, so any deadlock or re-entrant lock attempt causes the process to
hang forever with no error. Add a 30s timeout to both the regular query
acquirer and the transaction acquirer so contention surfaces as a clear
SqlError instead of a silent futex hang.

Closes #29395
@HrushiYadav
HrushiYadav force-pushed the fix/sqlite-lock-timeout branch from 5170cbf to 93cbb9b Compare June 15, 2026 07:38
@HrushiYadav

Copy link
Copy Markdown
Author

Friendly ping -- this adds a 30s timeout to the SQLite semaphore to prevent deadlock hangs. Any feedback or changes needed?

@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Automated PR Cleanup

Thank you for contributing to opencode.

Due to the high volume of PRs from users and AI agents, we periodically close older PRs using automated criteria so maintainers can focus review time on the most active and community-supported contributions.

This PR was closed because it matched the following cleanup criteria:

  • The PR was created more than 1 month ago
  • The PR had fewer than 2 positive reactions
  • Positive reactions are counted as thumbs-up, heart, celebration, or rocket reactions on the PR

PRs created within the last month are not affected by this cleanup.

If you believe this PR was closed incorrectly, or if you are still actively working on it, please leave a comment explaining why it should be reopened. A maintainer can review and reopen it if appropriate.

Thanks again for taking the time to contribute.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Concurrent opencode run instances deadlock during init (futex, no timeout) — second overlapping instance hangs forever

1 participant