File tree Expand file tree Collapse file tree 5 files changed +38
-14
lines changed
Expand file tree Collapse file tree 5 files changed +38
-14
lines changed Original file line number Diff line number Diff line change 22
33module 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
5462end
Original file line number Diff line number Diff 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
Original file line number Diff line number Diff 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
Original file line number Diff line number Diff line change 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
Original file line number Diff line number Diff line change 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
You can’t perform that action at this time.
0 commit comments