Skip to content

Commit 7b1cae1

Browse files
committed
Add new option. Review.
1 parent edb07f0 commit 7b1cae1

File tree

5 files changed

+38
-14
lines changed

5 files changed

+38
-14
lines changed

lib/table_sync/receiving/hooks/once.rb

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
module TableSync::Receiving::Hooks
44
class Once
5+
LOCK_KEY = "hook-once-lock-key"
6+
57
attr_reader :conditions, :handler, :lookup_code
68

79
def initialize(conditions:, handler:)
@@ -21,8 +23,9 @@ def perform(config:, targets:)
2123
targets.each do |target|
2224
next unless conditions?(target)
2325

24-
model.transaction(isolation: model.isolation_level(:repeatable)) do
25-
model.find_and_save(row: target, target_keys:) do |entry|
26+
keys = target.slice(*target_keys)
27+
model.try_advisory_lock(prepare_lock_key(keys)) do
28+
model.find_and_save(keys:) do |entry|
2629
next unless allow?(entry)
2730

2831
entry.hooks ||= []
@@ -50,5 +53,10 @@ def conditions?(row)
5053
row[column] == (conditions[column] || row[column])
5154
end
5255
end
56+
57+
def prepare_lock_key(row_keys)
58+
lock_keys = [LOCK_KEY] + row_keys.values
59+
Zlib.crc32(lock_keys.join(":")) % (2**31)
60+
end
5361
end
5462
end

lib/table_sync/receiving/model/active_record.rb

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,8 +129,16 @@ def after_commit(&)
129129
db.add_transaction_record(AfterCommitWrap.new(&))
130130
end
131131

132-
def find_and_save(row:, target_keys:)
133-
entry = raw_model.find_by(row.slice(*target_keys))
132+
def try_advisory_lock(lock_key)
133+
transaction do
134+
if db.query_value("SELECT pg_try_advisory_xact_lock(#{lock_key.to_i})")
135+
yield
136+
end
137+
end
138+
end
139+
140+
def find_and_save(keys:)
141+
entry = raw_model.find_by(keys)
134142
return unless entry
135143

136144
yield entry

lib/table_sync/receiving/model/sequel.rb

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,16 @@ def after_commit(&)
7676
db.after_commit(&)
7777
end
7878

79-
def find_and_save(row:, target_keys:)
80-
entry = dataset.first(row.slice(*target_keys))
79+
def try_advisory_lock(lock_key)
80+
transaction do
81+
if db.get(::Sequel.function(:pg_try_advisory_xact_lock, lock_key.to_i))
82+
yield
83+
end
84+
end
85+
end
86+
87+
def find_and_save(keys:)
88+
entry = dataset.first(keys)
8189
return unless entry
8290

8391
yield entry

spec/receiving/models/active_record_spec.rb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,18 +23,18 @@
2323
)
2424
end
2525

26-
let(:row) { { external_id: } }
26+
let(:keys) { { external_id: } }
2727

2828
it "finds and saves an entry" do
29-
model.find_and_save(row:, target_keys: [primary_key]) do |entry|
29+
model.find_and_save(keys:) do |entry|
3030
entry.online_status = true
3131
end
3232
expect(player.reload.online_status).to be_truthy
3333
end
3434

3535
it "does nothing" do
36-
row = { external_id: external_id + 1 }
37-
model.find_and_save(row:, target_keys: [primary_key]) do |entry|
36+
keys = { external_id: external_id + 1 }
37+
model.find_and_save(keys:) do |entry|
3838
entry.online_status = true
3939
end
4040
expect(player.reload.online_status).to be_falsy

spec/receiving/models/sequel_spec.rb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,18 +23,18 @@
2323
)
2424
end
2525

26-
let(:row) { { external_id: } }
26+
let(:keys) { { external_id: } }
2727

2828
it "finds and saves an entry" do
29-
model.find_and_save(row:, target_keys: [primary_key]) do |entry|
29+
model.find_and_save(keys:) do |entry|
3030
entry.online_status = true
3131
end
3232
expect(player.reload.online_status).to be_truthy
3333
end
3434

3535
it "does nothing" do
36-
row = { external_id: external_id + 1 }
37-
model.find_and_save(row:, target_keys: [primary_key]) do |entry|
36+
keys = { external_id: external_id + 1 }
37+
model.find_and_save(keys:) do |entry|
3838
entry.online_status = true
3939
end
4040
expect(player.reload.online_status).to be_falsy

0 commit comments

Comments
 (0)