-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #103 from gocardless/add-lock-databse
Add a new adapter to work the job with multiple database
- Loading branch information
Showing
9 changed files
with
191 additions
and
10 deletions.
There are no files selected for viewing
This file contains 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
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
# frozen_string_literal: true | ||
|
||
module Que | ||
module Adapters | ||
class ActiveRecordWithLock < Que::Adapters::ActiveRecord | ||
def initialize(job_connection_pool:, lock_connection_pool:) | ||
@job_connection_pool = job_connection_pool | ||
@lock_connection_pool = lock_connection_pool | ||
super | ||
end | ||
|
||
def checkout_activerecord_adapter(&block) | ||
checkout_lock_database_connection do | ||
@job_connection_pool.with_connection(&block) | ||
end | ||
end | ||
|
||
def checkout_lock_database_connection(&block) | ||
@lock_connection_pool.with_connection(&block) | ||
end | ||
|
||
def execute(command, params = []) | ||
case command | ||
when :lock_job | ||
queue, cursor = params | ||
lock_job_with_lock_database(queue, cursor) | ||
when :unlock_job | ||
job_id = params[0] | ||
unlock_job(job_id) | ||
else | ||
super | ||
end | ||
end | ||
|
||
def lock_job_with_lock_database(queue, cursor) | ||
result = [] | ||
loop do | ||
result = Que.execute(:find_job_to_lock, [queue, cursor]) | ||
|
||
break if result.empty? | ||
|
||
cursor = result.first["job_id"] | ||
break if pg_try_advisory_lock?(cursor) | ||
end | ||
result | ||
end | ||
|
||
def pg_try_advisory_lock?(job_id) | ||
checkout_lock_database_connection do |conn| | ||
conn.execute( | ||
"SELECT pg_try_advisory_lock(#{job_id})", | ||
).try(:first)&.fetch("pg_try_advisory_lock") | ||
end | ||
end | ||
|
||
def unlock_job(job_id) | ||
# If for any reason the connection that is used to get this advisory lock | ||
# is corrupted, the lock on this job_id would already be released when the | ||
# connection holding the lock goes bad. | ||
# Now, if a new connection tries to release the non existing lock this would just no op | ||
# by returning false and return a warning "WARNING: you don't own a lock of type ExclusiveLock" | ||
checkout_lock_database_connection do |conn| | ||
conn.execute("SELECT pg_advisory_unlock(#{job_id})") | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains 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
This file contains 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
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
# frozen_string_literal: true | ||
|
||
class LockDatabaseRecord < ActiveRecord::Base | ||
establish_connection( | ||
adapter: "postgresql", | ||
host: ENV.fetch("LOCK_PGHOST", "localhost"), | ||
user: ENV.fetch("LOCK_PGUSER", "postgres"), | ||
password: ENV.fetch("LOCK_PGPASSWORD", "password"), | ||
database: ENV.fetch("LOCK_PGDATABASE", "lock-test"), | ||
port: ENV.fetch("LOCK_PGPORT", 5434), | ||
pool: 5, | ||
) | ||
end | ||
|
||
class JobRecord < ActiveRecord::Base | ||
establish_connection( | ||
adapter: "postgresql", | ||
host: ENV.fetch("PGHOST", "localhost"), | ||
user: ENV.fetch("PGUSER", "ubuntu"), | ||
password: ENV.fetch("PGPASSWORD", "password"), | ||
database: ENV.fetch("PGDATABASE", "que-test"), | ||
) | ||
end | ||
|
||
def active_record_with_lock_adapter_connection | ||
Que::Adapters::ActiveRecordWithLock.new( | ||
job_connection_pool: JobRecord.connection_pool, | ||
lock_connection_pool: LockDatabaseRecord.connection_pool, | ||
) | ||
end |
This file contains 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
This file contains 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