fix: run distributed-lock heartbeat on a dedicated connection (issue #79) - #8
Merged
Merged
Conversation
…aisedapp#79) SQLiteDistributedLock ran its heartbeat timer's UpdateExpiration on the consumer's HangfireDbContext while the consumer used that same NoMutex (non-thread-safe) connection on another thread, causing AccessViolationException and storage corruption (upstream raisedapp#79). The heartbeat now obtains its own dedicated connection from the storage pool (storage.CreateAndOpenConnection()), so the timer thread never touches the caller's connection. Storage is plumbed through the two internal acquisition paths (HangfireSQLiteConnection.AcquireDistributedLock and ExpirationManager.RemoveExpireRows); the existing public Acquire overload is preserved and falls back to the legacy shared-connection behaviour when no storage is supplied. Bumps version to 0.5.1-beta. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017xW2zhMvrJChpY58hfJBeZ
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes the
AccessViolationException/ storage corruption reported upstream in raisedapp/Hangfire.Storage.SQLite#79.Root cause
SQLiteDistributedLockran its heartbeat timer'sUpdateExpirationon the consumer'sHangfireDbContext, while the consumer used that sameNoMutex(non-thread-safe) connection on another thread — e.g.RecurringJobSchedulerreleasing another lock, orExpirationManagerexecuting its delete. Two threads on one SQLite connection → memory corruption /AccessViolationException. (Same bug class already fixed for the sliding-timeout heartbeat in #3.)Fix
The heartbeat now obtains its own dedicated connection from the storage pool (
storage.CreateAndOpenConnection()), so the timer thread never touches the caller's connection. Storage is plumbed through the two internal acquisition paths (HangfireSQLiteConnection.AcquireDistributedLock,ExpirationManager.RemoveExpireRows). The publicAcquireoverload is preserved and falls back to the legacy shared-connection behaviour when no storage is supplied, so existing callers and tests are unaffected.Tests
Adds
SQLiteDistributedLockHeartbeatFacts: the heartbeat renewsExpireAton a dedicated connection and releases cleanly, plus a file-backed (WAL) concurrency test hammering the consumer connection while the heartbeat fires. Full suite: 203 passing.Bumps version to
0.5.1-beta.