Skip to content

Commit

Permalink
Clear previous changes before locking process for heartbeat
Browse files Browse the repository at this point in the history
For example, in case of a previous heartbeat failed because
of a DB issue (with SQLite depending on configuration, a
`BusyException` is not rare) and we still have the unpersisted
value in `last_heartbeat_at`, which means that `with_lock` will result
in:
```
RuntimeError: Locking a record with unpersisted changes is not supported
```

Fixes #350
  • Loading branch information
rosa committed Sep 16, 2024
1 parent 0749c60 commit aa64f12
Show file tree
Hide file tree
Showing 3 changed files with 18 additions and 2 deletions.
6 changes: 5 additions & 1 deletion app/models/solid_queue/process.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,11 @@ def self.register(**attributes)
end

def heartbeat
touch(:last_heartbeat_at)
# Clear any previous changes before locking, for example, in case a previous heartbeat
# failed because of a DB issue (with SQLite depending on configuration, a BusyException
# is not rare) and we still have the unpersisted value
restore_attributes
with_lock { touch(:last_heartbeat_at) }
end

def deregister(pruned: false)
Expand Down
2 changes: 1 addition & 1 deletion lib/solid_queue/processes/registrable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ def stop_heartbeat
end

def heartbeat
process.with_lock { process.heartbeat }
process.heartbeat
rescue ActiveRecord::RecordNotFound
self.process = nil
wake_up
Expand Down
12 changes: 12 additions & 0 deletions test/models/solid_queue/process_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -69,4 +69,16 @@ class SolidQueue::ProcessTest < ActiveSupport::TestCase
worker.stop
end
end

test "clear unregistered changes before locking for heartbeat" do
process = SolidQueue::Process.register(kind: "Supervisor", pid: 43, name: "supervisor-43")

# Pretend a heartbeat failed to persist
failed_heartbeat_at = 10.minutes.ago
process.last_heartbeat_at = failed_heartbeat_at

assert_changes -> { process.last_heartbeat_at } do
process.heartbeat
end
end
end

0 comments on commit aa64f12

Please sign in to comment.