@@ -809,6 +809,38 @@ def new_test_client(capture_buffer: @captured_commands)
809
809
)
810
810
::RedisClient ::Cluster . new ( config , pool : { timeout : TEST_TIMEOUT_SEC , size : 2 } )
811
811
end
812
+
813
+ # This test only makes sense for pooled connections; each fiber should check out
814
+ # a different connection
815
+ def test_two_concurrent_transactions
816
+ # This actually can't work unless we store the current transaction for a RedisClient::Cluster
817
+ # in a fiber-local variable. The best way to do that would be to add a dependency on concurrent-ruby,
818
+ # since otherwise fiber-local variables are prone to collisions and require finalizers to properly
819
+ # avoid leaks.
820
+ skip 'requires dependency on concurrent-ruby'
821
+
822
+ swap_keys_txn_factory = lambda { |key1 , key2 |
823
+ lambda {
824
+ @client . call ( 'SET' , key1 , 'value1' )
825
+ @client . call ( 'SET' , key2 , 'value2' )
826
+ @client . call_v ( [ 'WATCH' , key1 ] )
827
+ @client . call_v ( [ 'WATCH' , key2 ] )
828
+ old_value1 = @client . call_v ( [ 'GET' , key1 ] )
829
+ old_value2 = @client . call_v ( [ 'GET' , key2 ] )
830
+ Fiber . yield
831
+ @client . multi do |txn |
832
+ txn . call_v ( [ 'SET' , key1 , old_value2 ] )
833
+ txn . call_v ( [ 'SET' , key2 , old_value1 ] )
834
+ end
835
+ }
836
+ }
837
+
838
+ txn1 = Fiber . new ( &swap_keys_txn_factory . call ( '{slota}key1' , '{slota}key2' ) )
839
+ txn2 = Fiber . new ( &swap_keys_txn_factory . call ( '{slotb}key3' , '{slotb}key4' ) )
840
+ [ txn1 , txn2 , txn1 , txn2 ] . each ( &:resume )
841
+ # [txn1, txn1, txn2, txn2].each(&:resume)
842
+ [ txn1 , txn2 ] . join
843
+ end
812
844
end
813
845
end
814
846
end
0 commit comments