@@ -12,6 +12,7 @@ module RedisSingleFile
12
12
# @attr name [String] custom sync queue name
13
13
# @attr host [String] host for redis server
14
14
# @attr port [String] port for redis server
15
+ # @attr concurrency [Integer] simultaneous slots allowed
15
16
#
16
17
# @example Default lock name and infinite blocking
17
18
# semaphore = RedisSingleFile::Semaphore.new
@@ -65,23 +66,26 @@ def initialize(
65
66
redis : nil , # provide your own redis instance
66
67
name : Configuration . name , # designate queue name per session
67
68
host : Configuration . host , # designate redis host per session
68
- port : Configuration . port # designate redis port per session
69
+ port : Configuration . port , # designate redis port per session
70
+ concurrency : Configuration . concurrency # concurrent workers
69
71
)
70
72
@redis = redis || Redis . new ( host :, port :)
71
73
72
74
@mutex_val = name
73
75
@mutex_key = format ( Configuration . mutex_key , @mutex_val )
74
76
@queue_key = format ( Configuration . queue_key , @mutex_val )
77
+ @concurrency = concurrency . to_i
75
78
end
76
79
77
80
# Queues up client and waits for turn to execute. Returns nil
78
81
# when queue wait time expires.
79
82
#
80
83
# @param timeout [Integer] seconds for client to wait in queue
84
+ # @param concurrency [Integer] override concurrent workers
81
85
# @yieldreturn [...] response from synchronized block execution
82
86
# @return [nil] redis blpop timeout
83
- def synchronize ( timeout : 0 , &)
84
- synchronize! ( timeout :, &)
87
+ def synchronize ( timeout : 0 , concurrency : @concurrency , &)
88
+ synchronize! ( timeout :, concurrency : , &)
85
89
rescue QueueTimeoutError => _e
86
90
nil
87
91
end
@@ -90,14 +94,15 @@ def synchronize(timeout: 0, &)
90
94
# when queue wait time expires.
91
95
#
92
96
# @param timeout [Integer] seconds for blpop to wait in queue
97
+ # @param concurrency [Integer] override concurrent workers
93
98
# @yieldreturn [...] response from synchronized block execution
94
99
# @raise [QueueTimeoutError] redis blpop timeout
95
- def synchronize! ( timeout : 0 )
100
+ def synchronize! ( timeout : 0 , concurrency : @concurrency )
96
101
return unless block_given?
97
102
98
103
with_retry_protection do
99
- prime_queue unless redis . getset ( mutex_key , mutex_val )
100
- raise QueueTimeoutError unless redis . blpop ( queue_key , timeout :)
104
+ prime_queue ( concurrency ) unless redis . getset ( mutex_key , mutex_val )
105
+ raise QueueTimeoutError unless redis . blpop ( queue_key , timeout :)
101
106
102
107
redis . multi do
103
108
redis . persist ( mutex_key ) # unexpire during execution
@@ -108,7 +113,7 @@ def synchronize!(timeout: 0)
108
113
yield
109
114
ensure
110
115
# always cycle the queue when exiting
111
- unlock_queue if block_given?
116
+ unlock_queue ( concurrency ) if block_given?
112
117
end
113
118
114
119
private #===================================================================
@@ -119,20 +124,22 @@ def expire_in
119
124
@expire_in ||= Configuration . expire_in
120
125
end
121
126
122
- def prime_queue
127
+ def prime_queue ( concurrency )
123
128
with_retry_protection do
124
129
redis . multi do
125
- redis . del ( queue_key ) # remove existing queue
126
- redis . lpush ( queue_key , '1' ) # create and prime new queue
130
+ redis . del ( queue_key ) # remove existing queue
131
+ concurrency . times do # create and prime new queue
132
+ redis . lpush ( queue_key , '1' )
133
+ end
127
134
end
128
135
end
129
136
end
130
137
131
- def unlock_queue
138
+ def unlock_queue ( concurrency )
132
139
with_retry_protection do
133
140
redis . multi do
134
- # queue next client execution if queue is empty
135
- redis . lpush ( queue_key , '1' ) if redis . llen ( queue_key ) == 0
141
+ # queue next client execution if queue has space (concurrency)
142
+ redis . lpush ( queue_key , '1' ) if redis . llen ( queue_key ) < concurrency
136
143
redis . expire ( mutex_key , expire_in ) # set expiration for auto removal
137
144
redis . expire ( queue_key , expire_in ) # set expiration for auto removal
138
145
end
0 commit comments