Module: Raif::ArchiveAdvisoryLock
- Defined in:
- app/models/raif/archive_advisory_lock.rb
Overview
Shared advisory lock serializing every destructive archive operation: Raif::ArchiveModelCompletionsJob and Raif::Archive.purge_partition! must never interleave, or a concurrent archive run could write fresh objects into a partition prefix mid-purge and leave them behind.
Constant Summary collapse
- NAME =
"raif_archive_model_completions"
Class Method Summary collapse
-
.acquire ⇒ Object
Session-level and non-blocking: runs the block with the lock held and returns true, or returns false without running it when another session holds the lock.
Class Method Details
.acquire ⇒ Object
Session-level and non-blocking: runs the block with the lock held and returns true, or returns false without running it when another session holds the lock. Callers choose their busy behavior (the job skips the run; purge raises a retryable error). Adapters without advisory lock support (neither PG nor MySQL) run unguarded; hosts control scheduling anyway.
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
# File 'app/models/raif/archive_advisory_lock.rb', line 16 def self.acquire connection = Raif::ModelCompletion.connection # supports_advisory_locks?, never respond_to?(:get_advisory_lock): # AbstractAdapter defines get_advisory_lock as a nil-returning stub on # every adapter, so a respond_to? check passes on SQLite too and the nil # return would read as "lock busy", silently skipping the work forever. unless connection.respond_to?(:supports_advisory_locks?) && connection.supports_advisory_locks? Rails.logger.warn( "Raif::ArchiveAdvisoryLock: this database adapter does not support advisory locks; running unguarded " \ "(concurrent archive runs and partition purges cannot be excluded from each other)" ) yield return true end # Stable across processes (String#hash is per-process salted) and # within PG's signed bigint range. lock_id = Digest::SHA256.hexdigest(NAME)[0, 15].to_i(16) return false unless connection.get_advisory_lock(lock_id) begin yield true ensure connection.release_advisory_lock(lock_id) end end |