activejob-locking 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/HISTORY.md +5 -0
- data/README.md +34 -33
- data/lib/activejob/locking/adapters/memory.rb +3 -5
- data/lib/activejob/locking/adapters/redis-semaphore.rb +3 -2
- data/lib/activejob/locking/adapters/redlock.rb +3 -3
- data/lib/activejob/locking/adapters/suo-redis.rb +2 -2
- data/lib/activejob/locking/base.rb +14 -8
- data/lib/activejob/locking/options.rb +29 -18
- data/lib/activejob/locking/{perform.rb → serialized.rb} +4 -4
- data/lib/activejob/locking/{enqueue.rb → unique.rb} +8 -3
- data/lib/activejob-locking.rb +4 -4
- data/test/jobs/{perform_serially_job.rb → fail_job.rb} +4 -4
- data/test/jobs/{enqueue_drop_job.rb → serial_job.rb} +3 -3
- data/test/jobs/{enqueue_wait_job.rb → unique_job.rb} +3 -3
- data/test/serialized_tests.rb +63 -0
- data/test/test_helper.rb +3 -5
- data/test/test_serialized_memory.rb +11 -0
- data/test/{test_perform_redis_semaphore.rb → test_serialized_redis_semaphore.rb} +3 -3
- data/test/{test_enqueue_redlock.rb → test_serialized_redlock.rb} +3 -3
- data/test/{test_perform_suo_redis.rb → test_serialized_suo_redis.rb} +3 -3
- data/test/test_suite.rb +12 -0
- data/test/test_unique_memory.rb +12 -0
- data/test/{test_enqueue_redis_semaphore.rb → test_unique_redis_semaphore.rb} +3 -3
- data/test/{test_perform_redlock.rb → test_unique_redlock.rb} +3 -3
- data/test/{test_enqueue_suo_redis.rb → test_unique_suo_redis.rb} +3 -3
- data/test/unique_tests.rb +100 -0
- metadata +34 -22
- data/test/enqueue_tests.rb +0 -74
- data/test/jobs/enqueue_wait_large_timeout_job.rb +0 -16
- data/test/jobs/enqueue_wait_timeout_job.rb +0 -16
- data/test/jobs/perform_serially_large_timeout_job.rb +0 -16
- data/test/perform_tests.rb +0 -37
- data/test/test_enqueue_memory.rb +0 -45
- data/test/test_perform_memory.rb +0 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c1b1ea7063b5406f553e6d4282892299b6733cf5
|
4
|
+
data.tar.gz: 4fc8b9e358ec0583dc02eb6e6c069ef079653ad4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e84f37fc29ad783441943835f2157e530522dc52ff2e6953c047d029e2d19ad654c6c2f300ae1df277013c7f9e2cca8cd048002e234fb81f518f4572aff667e8
|
7
|
+
data.tar.gz: 9f05089c530aa8bcb0db266eda5210126d7d25634462495c448861b9057aa7d9ff037301081b74c1ca90de574fc62b9358bca76d88059c035383903e88a523a2
|
data/HISTORY.md
CHANGED
data/README.md
CHANGED
@@ -6,8 +6,8 @@ ActiveJob Locking
|
|
6
6
|
|
7
7
|
activejob-locking lets you control how ActiveJobs are enqueued and performed:
|
8
8
|
|
9
|
-
* Allow only one job to be enqueued at a time
|
10
|
-
* Allow only one job to be
|
9
|
+
* Allow only one job to be enqueued at a time - thus a "unique" job
|
10
|
+
* Allow only one job to be performed at a time - thus a "serialized" job
|
11
11
|
|
12
12
|
There are many other similar gems including [resque-lock-timeout](https://github.com/lantins/resque-lock-timeout),
|
13
13
|
[activejob-traffic-control](https://github.com/nickelser/activejob-traffic_control), [activejob-lock](https://github.com/idolweb/activejob-lock),
|
@@ -24,14 +24,14 @@ Add this line to your application's Gemfile:
|
|
24
24
|
gem 'activejob-locking'
|
25
25
|
```
|
26
26
|
|
27
|
-
|
27
|
+
Unique Jobs
|
28
28
|
------------
|
29
29
|
Sometime you only want to enqueue one instance of a job. No other similar job should be enqueued until the first one
|
30
30
|
is completed.
|
31
31
|
|
32
32
|
```ruby
|
33
|
-
class
|
34
|
-
include ActiveJob::Locking::
|
33
|
+
class UniqueJob < ActiveJob::Base
|
34
|
+
include ActiveJob::Locking::Unique
|
35
35
|
|
36
36
|
# Make sure the lock_key is always the same
|
37
37
|
def lock_key
|
@@ -48,14 +48,14 @@ never be enqueued or it will wait to the first job is performed. That is contro
|
|
48
48
|
[options](##options) described below.
|
49
49
|
|
50
50
|
|
51
|
-
|
51
|
+
Serialized Jobs
|
52
52
|
------------
|
53
53
|
Sometime you only want to perform one instance of a job at a time. No other similar job should be performed until the first one
|
54
54
|
is completed.
|
55
55
|
|
56
56
|
```ruby
|
57
|
-
class
|
58
|
-
include ActiveJob::Locking::
|
57
|
+
class SerializedJob < ActiveJob::Base
|
58
|
+
include ActiveJob::Locking::Serialized
|
59
59
|
|
60
60
|
# Make sure the lock_key is always the same
|
61
61
|
def lock_key
|
@@ -136,7 +136,7 @@ available at:
|
|
136
136
|
```ruby
|
137
137
|
ActiveJob::Locking.options
|
138
138
|
```
|
139
|
-
This should be updated using a Rails initializer. Each job class can override
|
139
|
+
This should be updated using a Rails initializer. Each job class can override individual options as it sees fit.
|
140
140
|
|
141
141
|
### Adapter
|
142
142
|
|
@@ -151,7 +151,7 @@ Locally update:
|
|
151
151
|
|
152
152
|
```ruby
|
153
153
|
class ExampleJob < ActiveJob::Base
|
154
|
-
include ActiveJob::Locking::
|
154
|
+
include ActiveJob::Locking::Serialized
|
155
155
|
|
156
156
|
self.adapter = ActiveJob::Locking::Adapters::SuoRedis
|
157
157
|
end
|
@@ -171,58 +171,59 @@ Locally update:
|
|
171
171
|
|
172
172
|
```ruby
|
173
173
|
class ExampleJob < ActiveJob::Base
|
174
|
-
include ActiveJob::Locking::
|
174
|
+
include ActiveJob::Locking::Serialized
|
175
175
|
|
176
176
|
self.hosts = 'localhost'
|
177
177
|
end
|
178
178
|
```
|
179
179
|
|
180
|
-
###
|
180
|
+
### lock_acquire_time
|
181
181
|
|
182
|
-
The is the
|
183
|
-
|
184
|
-
contrast to aggressively removing locks for running jobs even if no other job has requested them.
|
185
|
-
|
186
|
-
The value is specified in seconds and defaults to 100.
|
182
|
+
The is the timeout for acquiring a lock. The value is specified in seconds and defaults to 1. It must
|
183
|
+
be greater than zero and cannot be nil.
|
187
184
|
|
188
185
|
Globally update:
|
189
186
|
|
190
187
|
```ruby
|
191
|
-
ActiveJob::Locking.options.
|
188
|
+
ActiveJob::Locking.options.lock_acquire_time = 1
|
192
189
|
```
|
193
|
-
Locally update
|
190
|
+
Locally update:
|
194
191
|
|
195
192
|
```ruby
|
196
193
|
class ExampleJob < ActiveJob::Base
|
197
|
-
include ActiveJob::Locking::
|
194
|
+
include ActiveJob::Locking::Unique
|
198
195
|
|
199
|
-
self.
|
196
|
+
self.lock_acquire_time = 1
|
200
197
|
end
|
201
198
|
```
|
199
|
+
This greatly influences how enqueuing behavior works. If the timeout is short, then jobs that are waiting to
|
200
|
+
be enqueued are dropped and the before_enqueue callback will fail. If the timeout is infinite, then jobs will wait
|
201
|
+
in turn to get enqueued. If the timeout is somewhere in between then it will depend on how long the jobs
|
202
|
+
take to execute.
|
202
203
|
|
203
|
-
###
|
204
|
+
### lock_time
|
204
205
|
|
205
|
-
The is the
|
206
|
-
|
206
|
+
The is the time to live for any acquired locks. For most locking gems this is mapped to their concept of "stale" locks.
|
207
|
+
That means that if an attempt is made to access the lock after it is expired, it will be considered unlocked. That is in
|
208
|
+
contrast to aggressively removing locks for running jobs even if no other job has requested them.
|
209
|
+
|
210
|
+
The value is specified in seconds and defaults to 100.
|
207
211
|
|
208
212
|
Globally update:
|
209
213
|
|
210
214
|
```ruby
|
211
|
-
ActiveJob::Locking.options.
|
215
|
+
ActiveJob::Locking.options.lock_time = 100
|
212
216
|
```
|
213
|
-
Locally update
|
217
|
+
Locally update:
|
214
218
|
|
215
219
|
```ruby
|
216
220
|
class ExampleJob < ActiveJob::Base
|
217
|
-
include ActiveJob::Locking::
|
221
|
+
include ActiveJob::Locking::Serialized
|
218
222
|
|
219
|
-
self.
|
223
|
+
self.lock_time = 100
|
220
224
|
end
|
221
225
|
```
|
222
|
-
|
223
|
-
be enqueued are dropped and the before_enqueue callback will fail. If the timeout is infinite, then jobs will wait
|
224
|
-
in turn to get enqueued. If the timeout is somewhere in between then it will depend on how long the jobs
|
225
|
-
take to execute.
|
226
|
+
|
226
227
|
|
227
228
|
### AdapterOptions
|
228
229
|
|
@@ -238,7 +239,7 @@ Locally update (notice the different method name to avoid potential conflicts):
|
|
238
239
|
|
239
240
|
```ruby
|
240
241
|
class ExampleJob < ActiveJob::Base
|
241
|
-
include ActiveJob::Locking::
|
242
|
+
include ActiveJob::Locking::Unique
|
242
243
|
|
243
244
|
self.adapter_options = {}
|
244
245
|
end
|
@@ -2,8 +2,6 @@ module ActiveJob
|
|
2
2
|
module Locking
|
3
3
|
module Adapters
|
4
4
|
class Memory < Base
|
5
|
-
attr_reader :timeout
|
6
|
-
|
7
5
|
@hash = Hash.new
|
8
6
|
@mutex = Mutex.new
|
9
7
|
|
@@ -39,8 +37,8 @@ module ActiveJob
|
|
39
37
|
end
|
40
38
|
|
41
39
|
def lock
|
42
|
-
finish = Time.now + self.options.
|
43
|
-
sleep_time = [5, self.options.
|
40
|
+
finish = Time.now + self.options.lock_acquire_time
|
41
|
+
sleep_time = [5, self.options.lock_acquire_time / 5].min
|
44
42
|
|
45
43
|
begin
|
46
44
|
lock = self.class.lock(key)
|
@@ -48,7 +46,7 @@ module ActiveJob
|
|
48
46
|
sleep(sleep_time)
|
49
47
|
end while Time.now < finish
|
50
48
|
|
51
|
-
|
49
|
+
false
|
52
50
|
end
|
53
51
|
|
54
52
|
def unlock
|
@@ -6,13 +6,14 @@ module ActiveJob
|
|
6
6
|
class RedisSemaphore < Base
|
7
7
|
def create_lock_manager
|
8
8
|
mapped_options = {host: self.options.hosts,
|
9
|
-
|
9
|
+
resources: 1,
|
10
|
+
stale_client_timeout: self.options.lock_time}.merge(self.options.adapter_options)
|
10
11
|
|
11
12
|
Redis::Semaphore.new(self.key, mapped_options)
|
12
13
|
end
|
13
14
|
|
14
15
|
def lock
|
15
|
-
self.lock_token = self.lock_manager.lock(self.options.
|
16
|
+
self.lock_token = self.lock_manager.lock(self.options.lock_acquire_time)
|
16
17
|
end
|
17
18
|
|
18
19
|
def unlock
|
@@ -6,14 +6,14 @@ module ActiveJob
|
|
6
6
|
class Redlock < Base
|
7
7
|
def create_lock_manager
|
8
8
|
mapped_options = self.options.adapter_options
|
9
|
-
mapped_options[:retry_count] =
|
10
|
-
mapped_options[:retry_delay] =
|
9
|
+
mapped_options[:retry_count] = 2 # Try to get the lock and then try again when timeout is expiring--
|
10
|
+
mapped_options[:retry_delay] = self.options.lock_acquire_time * 1000 # convert from seconds to milliseconds
|
11
11
|
|
12
12
|
::Redlock::Client.new(Array(self.options.hosts), mapped_options)
|
13
13
|
end
|
14
14
|
|
15
15
|
def lock
|
16
|
-
self.lock_token = self.lock_manager.lock(self.key, self.options.
|
16
|
+
self.lock_token = self.lock_manager.lock(self.key, self.options.lock_time * 1000)
|
17
17
|
end
|
18
18
|
|
19
19
|
def unlock
|
@@ -6,8 +6,8 @@ module ActiveJob
|
|
6
6
|
class SuoRedis < Base
|
7
7
|
def create_lock_manager
|
8
8
|
mapped_options = {connection: {host: self.options.hosts},
|
9
|
-
stale_lock_expiration: self.options.
|
10
|
-
acquisition_timeout: self.options.
|
9
|
+
stale_lock_expiration: self.options.lock_time,
|
10
|
+
acquisition_timeout: self.options.lock_acquire_time}
|
11
11
|
|
12
12
|
Suo::Client::Redis.new(self.key, mapped_options)
|
13
13
|
end
|
@@ -7,15 +7,15 @@ module ActiveJob
|
|
7
7
|
def lock_options
|
8
8
|
@lock_options ||= ActiveJob::Locking::Options.new
|
9
9
|
end
|
10
|
-
delegate :adapter, :hosts, :lock_time, :
|
11
|
-
delegate :adapter=, :hosts=, :lock_time=, :
|
10
|
+
delegate :adapter, :hosts, :lock_time, :lock_acquire_time, :adapter_options, to: :lock_options
|
11
|
+
delegate :adapter=, :hosts=, :lock_time=, :lock_acquire_time=, :adapter_options=, to: :lock_options
|
12
12
|
end
|
13
13
|
|
14
14
|
included do
|
15
|
-
# We need to serialize the lock token because it could be released in a different process
|
15
|
+
# We need to serialize the lock token that some gems create because it could be released in a different process
|
16
16
|
def serialize
|
17
17
|
result = super
|
18
|
-
result
|
18
|
+
result['lock_token'] = self.adapter.lock_token
|
19
19
|
result
|
20
20
|
end
|
21
21
|
|
@@ -29,11 +29,17 @@ module ActiveJob
|
|
29
29
|
end
|
30
30
|
|
31
31
|
def adapter
|
32
|
-
|
33
|
-
|
32
|
+
@adapter ||= begin
|
33
|
+
# Make sure arguments are deserialized so calling lock key is safe
|
34
|
+
deserialize_arguments_if_needed
|
34
35
|
|
35
|
-
|
36
|
-
|
36
|
+
# Merge local and global options
|
37
|
+
merged_options = ActiveJob::Locking.options.dup.merge(self.class.lock_options)
|
38
|
+
|
39
|
+
# Remember the lock might be acquired in one process and released in another
|
40
|
+
merged_options.adapter.new(self.lock_key, merged_options)
|
41
|
+
end
|
42
|
+
@adapter
|
37
43
|
end
|
38
44
|
end
|
39
45
|
end
|
@@ -5,30 +5,41 @@ module ActiveJob
|
|
5
5
|
class Options
|
6
6
|
attr_accessor :adapter
|
7
7
|
attr_accessor :hosts
|
8
|
-
attr_accessor :
|
9
|
-
attr_accessor :
|
8
|
+
attr_accessor :lock_time
|
9
|
+
attr_accessor :lock_acquire_time
|
10
10
|
attr_accessor :adapter_options
|
11
11
|
|
12
|
-
alias :lock_time :time
|
13
|
-
alias :lock_time= :time=
|
14
|
-
alias :lock_acquire_timeout :timeout
|
15
|
-
alias :lock_acquire_timeout= :timeout=
|
16
|
-
|
17
12
|
def initialize(options = {})
|
18
13
|
@adapter = options[:adapter]
|
19
14
|
@hosts = options[:hosts]
|
20
|
-
@
|
21
|
-
@
|
15
|
+
@lock_time = options[:lock_time]
|
16
|
+
@lock_acquire_time = options[:lock_acquire_time]
|
22
17
|
@adapter_options = options[:adapter_options]
|
23
18
|
end
|
24
19
|
|
25
|
-
def
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
20
|
+
def lock_time=(value)
|
21
|
+
case value
|
22
|
+
when NilClass
|
23
|
+
raise(ArgumentError, 'Lock time must be set')
|
24
|
+
when ActiveSupport::Duration
|
25
|
+
@lock_time = value.value
|
26
|
+
when 0
|
27
|
+
raise(ArgumentError, 'Lock time must be greater than zero')
|
28
|
+
else
|
29
|
+
@lock_time = value
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def lock_acquire_time=(value)
|
34
|
+
case value
|
35
|
+
when NilClass
|
36
|
+
raise(ArgumentError, 'Lock acquire time must be set')
|
37
|
+
when ActiveSupport::Duration
|
38
|
+
@lock_acquire_time = value.value
|
39
|
+
when 0
|
40
|
+
raise(ArgumentError, 'Lock acquire time must be greater than zero')
|
41
|
+
else
|
42
|
+
@lock_acquire_time = value
|
32
43
|
end
|
33
44
|
end
|
34
45
|
|
@@ -36,8 +47,8 @@ module ActiveJob
|
|
36
47
|
result = self.dup
|
37
48
|
result.adapter = other.adapter if other.adapter
|
38
49
|
result.hosts = other.hosts if other.hosts
|
39
|
-
result.
|
40
|
-
result.
|
50
|
+
result.lock_time = other.lock_time if other.lock_time
|
51
|
+
result.lock_acquire_time = other.lock_acquire_time if other.lock_acquire_time
|
41
52
|
result.adapter_options = other.adapter_options if other.adapter_options
|
42
53
|
result
|
43
54
|
end
|
@@ -1,20 +1,20 @@
|
|
1
1
|
module ActiveJob
|
2
2
|
module Locking
|
3
|
-
module
|
3
|
+
module Serialized
|
4
4
|
extend ::ActiveSupport::Concern
|
5
5
|
|
6
6
|
included do
|
7
7
|
include ::ActiveJob::Locking::Base
|
8
8
|
|
9
9
|
around_perform do |job, block|
|
10
|
-
if
|
10
|
+
if job.adapter.lock
|
11
11
|
begin
|
12
12
|
block.call
|
13
13
|
ensure
|
14
|
-
|
14
|
+
job.adapter.unlock
|
15
15
|
end
|
16
16
|
else
|
17
|
-
|
17
|
+
job.class.set(wait: job.class.lock_acquire_time).perform_later(*job.arguments)
|
18
18
|
end
|
19
19
|
end
|
20
20
|
end
|
@@ -1,18 +1,23 @@
|
|
1
1
|
module ActiveJob
|
2
2
|
module Locking
|
3
|
-
module
|
3
|
+
module Unique
|
4
4
|
extend ::ActiveSupport::Concern
|
5
5
|
|
6
6
|
included do
|
7
7
|
include ::ActiveJob::Locking::Base
|
8
8
|
|
9
9
|
before_enqueue do |job|
|
10
|
-
lock =
|
10
|
+
lock = job.adapter.lock
|
11
11
|
throw :abort unless lock
|
12
12
|
end
|
13
13
|
|
14
|
-
|
14
|
+
rescue_from(Exception) do |exception|
|
15
15
|
self.adapter.unlock
|
16
|
+
raise
|
17
|
+
end
|
18
|
+
|
19
|
+
after_perform do |job|
|
20
|
+
job.adapter.unlock
|
16
21
|
end
|
17
22
|
end
|
18
23
|
end
|
data/lib/activejob-locking.rb
CHANGED
@@ -2,8 +2,8 @@ require 'activejob/locking/adapters/base'
|
|
2
2
|
require 'activejob/locking/adapters/memory'
|
3
3
|
|
4
4
|
require 'activejob/locking/base'
|
5
|
-
require 'activejob/locking/
|
6
|
-
require 'activejob/locking/
|
5
|
+
require 'activejob/locking/unique'
|
6
|
+
require 'activejob/locking/serialized'
|
7
7
|
|
8
8
|
require 'activejob/locking/options'
|
9
9
|
|
@@ -11,8 +11,8 @@ module ActiveJob
|
|
11
11
|
module Locking
|
12
12
|
@options = ActiveJob::Locking::Options.new(adapter: ActiveJob::Locking::Adapters::Memory,
|
13
13
|
hosts: 'localhost',
|
14
|
-
|
15
|
-
|
14
|
+
lock_time: 100,
|
15
|
+
lock_acquire_time: 1,
|
16
16
|
adapter_options: {})
|
17
17
|
|
18
18
|
def self.options
|
@@ -1,7 +1,7 @@
|
|
1
|
-
class
|
2
|
-
include ActiveJob::Locking::
|
1
|
+
class FailJob < ActiveJob::Base
|
2
|
+
include ActiveJob::Locking::Unique
|
3
3
|
|
4
|
-
self.
|
4
|
+
self.lock_acquire_time = 2
|
5
5
|
|
6
6
|
# We want the job ids to be all the same for testing
|
7
7
|
def lock_key
|
@@ -10,6 +10,6 @@ class PerformSeriallyJob < ActiveJob::Base
|
|
10
10
|
|
11
11
|
# Pass in index so we can distinguish different jobs
|
12
12
|
def perform(index, sleep_time)
|
13
|
-
|
13
|
+
raise(ArgumentError, 'Job failed')
|
14
14
|
end
|
15
15
|
end
|
@@ -1,7 +1,7 @@
|
|
1
|
-
class
|
2
|
-
include ActiveJob::Locking::
|
1
|
+
class SerialJob < ActiveJob::Base
|
2
|
+
include ActiveJob::Locking::Serialized
|
3
3
|
|
4
|
-
self.
|
4
|
+
self.lock_acquire_time = 2
|
5
5
|
|
6
6
|
# We want the job ids to be all the same for testing
|
7
7
|
def lock_key
|
@@ -1,7 +1,7 @@
|
|
1
|
-
class
|
2
|
-
include ActiveJob::Locking::
|
1
|
+
class UniqueJob < ActiveJob::Base
|
2
|
+
include ActiveJob::Locking::Unique
|
3
3
|
|
4
|
-
self.
|
4
|
+
self.lock_acquire_time = 2
|
5
5
|
|
6
6
|
# We want the job ids to be all the same for testing
|
7
7
|
def lock_key
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require File.expand_path('../test_helper', __FILE__)
|
2
|
+
|
3
|
+
module SerializedTests
|
4
|
+
def test_one_completed
|
5
|
+
assert_equal(0, ActiveJob::Base.queue_adapter.enqueued_jobs.count)
|
6
|
+
assert_equal(0, ActiveJob::Base.queue_adapter.performed_jobs.count)
|
7
|
+
|
8
|
+
start_time = Time.now
|
9
|
+
sleep_time = SerialJob.lock_acquire_time / 0.9
|
10
|
+
threads = 3.times.map do |i|
|
11
|
+
Thread.new do
|
12
|
+
SerialJob.perform_later(i, sleep_time)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# All the threads will complete after the sleep time has expired - since two jobs get requeued
|
17
|
+
threads.each {|thread| thread.join}
|
18
|
+
assert_equal(2, ActiveJob::Base.queue_adapter.enqueued_jobs.count)
|
19
|
+
assert_equal(3, ActiveJob::Base.queue_adapter.performed_jobs.count)
|
20
|
+
|
21
|
+
assert(Time.now - start_time > (1 * sleep_time))
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_some_completed
|
25
|
+
assert_equal(0, ActiveJob::Base.queue_adapter.enqueued_jobs.count)
|
26
|
+
assert_equal(0, ActiveJob::Base.queue_adapter.performed_jobs.count)
|
27
|
+
|
28
|
+
start_time = Time.now
|
29
|
+
sleep_time = SerialJob.lock_acquire_time / 1.9
|
30
|
+
threads = 3.times.map do |i|
|
31
|
+
Thread.new do
|
32
|
+
SerialJob.perform_later(i, sleep_time)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# All the threads will complete after the sleep time has expired - since two jobs get requeued
|
37
|
+
threads.each {|thread| thread.join}
|
38
|
+
assert_equal(1, ActiveJob::Base.queue_adapter.enqueued_jobs.count)
|
39
|
+
assert_equal(3, ActiveJob::Base.queue_adapter.performed_jobs.count)
|
40
|
+
|
41
|
+
assert(Time.now - start_time > (1 * sleep_time))
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_all_completed
|
45
|
+
assert_equal(0, ActiveJob::Base.queue_adapter.enqueued_jobs.count)
|
46
|
+
assert_equal(0, ActiveJob::Base.queue_adapter.performed_jobs.count)
|
47
|
+
|
48
|
+
start_time = Time.now
|
49
|
+
sleep_time = SerialJob.lock_acquire_time / 4
|
50
|
+
threads = 3.times.map do |i|
|
51
|
+
Thread.new do
|
52
|
+
SerialJob.perform_later(i, sleep_time)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# All the threads will complete after the sleep time has expired - since two jobs get requeued
|
57
|
+
threads.each {|thread| thread.join}
|
58
|
+
assert_equal(0, ActiveJob::Base.queue_adapter.enqueued_jobs.count)
|
59
|
+
assert_equal(3, ActiveJob::Base.queue_adapter.performed_jobs.count)
|
60
|
+
|
61
|
+
assert(Time.now - start_time > (1 * sleep_time))
|
62
|
+
end
|
63
|
+
end
|
data/test/test_helper.rb
CHANGED
@@ -11,11 +11,9 @@ require 'activejob/locking/adapters/redis-semaphore'
|
|
11
11
|
require 'activejob/locking/adapters/redlock'
|
12
12
|
require 'activejob/locking/adapters/suo-redis'
|
13
13
|
|
14
|
-
require_relative './jobs/
|
15
|
-
require_relative './jobs/
|
16
|
-
require_relative './jobs/
|
17
|
-
require_relative './jobs/enqueue_wait_large_timeout_job'
|
18
|
-
require_relative './jobs/perform_serially_job'
|
14
|
+
require_relative './jobs/unique_job'
|
15
|
+
require_relative './jobs/fail_job'
|
16
|
+
require_relative './jobs/serial_job'
|
19
17
|
|
20
18
|
def redis_reset
|
21
19
|
Kernel.system('redis-cli FLUSHALL')
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require_relative('./serialized_tests')
|
2
|
+
|
3
|
+
class SerializedMemory < MiniTest::Test
|
4
|
+
include SerializedTests
|
5
|
+
|
6
|
+
def setup
|
7
|
+
ActiveJob::Base.queue_adapter = :test
|
8
|
+
ActiveJob::Base.queue_adapter.perform_enqueued_jobs = true
|
9
|
+
ActiveJob::Locking.options.adapter = ActiveJob::Locking::Adapters::Memory
|
10
|
+
end
|
11
|
+
end
|
data/test/test_suite.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
%w(
|
2
|
+
test_serialized_memory
|
3
|
+
test_serialized_redis_semaphore
|
4
|
+
test_serialized_redlock
|
5
|
+
test_serialized_suo_redis
|
6
|
+
test_unique_memory
|
7
|
+
test_unique_redis_semaphore
|
8
|
+
test_unique_redlock
|
9
|
+
test_unique_suo_redis
|
10
|
+
).each do |test|
|
11
|
+
require File.expand_path("../#{test}", __FILE__)
|
12
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require_relative('./unique_tests')
|
2
|
+
|
3
|
+
class UniqueMemoryTest < MiniTest::Test
|
4
|
+
include UniqueTests
|
5
|
+
|
6
|
+
def setup
|
7
|
+
ActiveJob::Locking::Adapters::Memory.reset
|
8
|
+
ActiveJob::Base.queue_adapter = :test
|
9
|
+
ActiveJob::Base.queue_adapter.perform_enqueued_jobs = true
|
10
|
+
ActiveJob::Locking.options.adapter = ActiveJob::Locking::Adapters::Memory
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
require File.expand_path('../test_helper', __FILE__)
|
2
|
+
|
3
|
+
module UniqueTests
|
4
|
+
def test_none_performed
|
5
|
+
ActiveJob::Base.queue_adapter.perform_enqueued_jobs = false
|
6
|
+
|
7
|
+
assert_equal(0, ActiveJob::Base.queue_adapter.enqueued_jobs.count)
|
8
|
+
assert_equal(0, ActiveJob::Base.queue_adapter.performed_jobs.count)
|
9
|
+
|
10
|
+
sleep_time = UniqueJob.lock_acquire_time
|
11
|
+
threads = 3.times.map do |i|
|
12
|
+
Thread.new do
|
13
|
+
UniqueJob.perform_later(i, sleep_time)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
threads.each {|thread| thread.join}
|
18
|
+
assert_equal(1, ActiveJob::Base.queue_adapter.enqueued_jobs.count)
|
19
|
+
assert_equal(0, ActiveJob::Base.queue_adapter.performed_jobs.count)
|
20
|
+
ensure
|
21
|
+
ActiveJob::Base.queue_adapter.perform_enqueued_jobs = true
|
22
|
+
ActiveJob::Base.queue_adapter.enqueued_jobs.clear
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_one_performed
|
26
|
+
assert_equal(0, ActiveJob::Base.queue_adapter.enqueued_jobs.count)
|
27
|
+
assert_equal(0, ActiveJob::Base.queue_adapter.performed_jobs.count)
|
28
|
+
|
29
|
+
sleep_time = UniqueJob.lock_acquire_time * 2
|
30
|
+
threads = 3.times.map do |i|
|
31
|
+
Thread.new do
|
32
|
+
UniqueJob.perform_later(i, sleep_time)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
threads.each {|thread| thread.join}
|
37
|
+
assert_equal(0, ActiveJob::Base.queue_adapter.enqueued_jobs.count)
|
38
|
+
assert_equal(1, ActiveJob::Base.queue_adapter.performed_jobs.count)
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_all_performed
|
42
|
+
assert_equal(0, ActiveJob::Base.queue_adapter.enqueued_jobs.count)
|
43
|
+
assert_equal(0, ActiveJob::Base.queue_adapter.performed_jobs.count)
|
44
|
+
|
45
|
+
start_time = Time.now
|
46
|
+
sleep_time = UniqueJob.lock_acquire_time / 4.0
|
47
|
+
threads = 3.times.map do |i|
|
48
|
+
Thread.new do
|
49
|
+
UniqueJob.perform_later(i, sleep_time)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
threads.each {|thread| thread.join}
|
54
|
+
|
55
|
+
assert_equal(0, ActiveJob::Base.queue_adapter.enqueued_jobs.count)
|
56
|
+
assert_equal(threads.count, ActiveJob::Base.queue_adapter.performed_jobs.count)
|
57
|
+
assert(Time.now - start_time > (threads.count * sleep_time))
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_some_performed
|
61
|
+
assert_equal(0, ActiveJob::Base.queue_adapter.enqueued_jobs.count)
|
62
|
+
assert_equal(0, ActiveJob::Base.queue_adapter.performed_jobs.count)
|
63
|
+
|
64
|
+
start_time = Time.now
|
65
|
+
sleep_time = UniqueJob.lock_acquire_time / 2.0
|
66
|
+
threads = 3.times.map do |i|
|
67
|
+
Thread.new do
|
68
|
+
UniqueJob.perform_later(i, sleep_time)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
threads.each {|thread| thread.join}
|
73
|
+
|
74
|
+
assert_equal(0, ActiveJob::Base.queue_adapter.enqueued_jobs.count)
|
75
|
+
assert_equal(threads.count - 1, ActiveJob::Base.queue_adapter.performed_jobs.count)
|
76
|
+
assert(Time.now - start_time > ((threads.count - 1) * sleep_time))
|
77
|
+
end
|
78
|
+
|
79
|
+
def test_fail
|
80
|
+
assert_equal(0, ActiveJob::Base.queue_adapter.enqueued_jobs.count)
|
81
|
+
assert_equal(0, ActiveJob::Base.queue_adapter.performed_jobs.count)
|
82
|
+
|
83
|
+
start_time = Time.now
|
84
|
+
sleep_time = UniqueJob.lock_acquire_time
|
85
|
+
threads = 3.times.map do |i|
|
86
|
+
Thread.new do
|
87
|
+
begin
|
88
|
+
FailJob.perform_later(i, sleep_time)
|
89
|
+
rescue => e
|
90
|
+
# do nothing
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
threads.each {|thread| thread.join}
|
96
|
+
|
97
|
+
assert_equal(0, ActiveJob::Base.queue_adapter.enqueued_jobs.count)
|
98
|
+
assert_equal(threads.count, ActiveJob::Base.queue_adapter.performed_jobs.count)
|
99
|
+
end
|
100
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activejob-locking
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Charlie Savage
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-06-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activejob
|
@@ -38,6 +38,20 @@ dependencies:
|
|
38
38
|
- - ">"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: 5.10.0
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: redis-mutex
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: redis-semaphore
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -84,7 +98,7 @@ description: |
|
|
84
98
|
activejob-locking lets you control how ActiveJobs are enqueued and performed:
|
85
99
|
|
86
100
|
Allow only one job to be enqueued at a time (based on a lock_id)
|
87
|
-
Allow only one job to be
|
101
|
+
Allow only one job to be performed at a time (also based on a lock_id)
|
88
102
|
email:
|
89
103
|
executables: []
|
90
104
|
extensions: []
|
@@ -102,26 +116,24 @@ files:
|
|
102
116
|
- lib/activejob/locking/adapters/redlock.rb
|
103
117
|
- lib/activejob/locking/adapters/suo-redis.rb
|
104
118
|
- lib/activejob/locking/base.rb
|
105
|
-
- lib/activejob/locking/enqueue.rb
|
106
119
|
- lib/activejob/locking/options.rb
|
107
|
-
- lib/activejob/locking/
|
108
|
-
-
|
109
|
-
- test/jobs/
|
110
|
-
- test/jobs/
|
111
|
-
- test/jobs/
|
112
|
-
- test/
|
113
|
-
- test/jobs/perform_serially_job.rb
|
114
|
-
- test/jobs/perform_serially_large_timeout_job.rb
|
115
|
-
- test/perform_tests.rb
|
116
|
-
- test/test_enqueue_memory.rb
|
117
|
-
- test/test_enqueue_redis_semaphore.rb
|
118
|
-
- test/test_enqueue_redlock.rb
|
119
|
-
- test/test_enqueue_suo_redis.rb
|
120
|
+
- lib/activejob/locking/serialized.rb
|
121
|
+
- lib/activejob/locking/unique.rb
|
122
|
+
- test/jobs/fail_job.rb
|
123
|
+
- test/jobs/serial_job.rb
|
124
|
+
- test/jobs/unique_job.rb
|
125
|
+
- test/serialized_tests.rb
|
120
126
|
- test/test_helper.rb
|
121
|
-
- test/
|
122
|
-
- test/
|
123
|
-
- test/
|
124
|
-
- test/
|
127
|
+
- test/test_serialized_memory.rb
|
128
|
+
- test/test_serialized_redis_semaphore.rb
|
129
|
+
- test/test_serialized_redlock.rb
|
130
|
+
- test/test_serialized_suo_redis.rb
|
131
|
+
- test/test_suite.rb
|
132
|
+
- test/test_unique_memory.rb
|
133
|
+
- test/test_unique_redis_semaphore.rb
|
134
|
+
- test/test_unique_redlock.rb
|
135
|
+
- test/test_unique_suo_redis.rb
|
136
|
+
- test/unique_tests.rb
|
125
137
|
homepage: http://github.com/cfis/activejob-locking
|
126
138
|
licenses:
|
127
139
|
- MIT
|
@@ -142,7 +154,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
142
154
|
version: '0'
|
143
155
|
requirements: []
|
144
156
|
rubyforge_project:
|
145
|
-
rubygems_version: 2.6.
|
157
|
+
rubygems_version: 2.6.11
|
146
158
|
signing_key:
|
147
159
|
specification_version: 4
|
148
160
|
summary: ActiveJob locking to control how jobs are enqueued and performed.
|
data/test/enqueue_tests.rb
DELETED
@@ -1,74 +0,0 @@
|
|
1
|
-
require File.expand_path('../test_helper', __FILE__)
|
2
|
-
|
3
|
-
module EnqueueTests
|
4
|
-
def test_drop
|
5
|
-
assert_equal(0, ActiveJob::Base.queue_adapter.enqueued_jobs.count)
|
6
|
-
|
7
|
-
start_time = Time.now
|
8
|
-
sleep_time = 2
|
9
|
-
threads = 2.times.map do |i|
|
10
|
-
Thread.new do
|
11
|
-
EnqueueDropJob.perform_later(i, sleep_time)
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
threads.each {|thread| thread.join}
|
16
|
-
assert_equal(0, ActiveJob::Base.queue_adapter.enqueued_jobs.count)
|
17
|
-
assert_equal(1, ActiveJob::Base.queue_adapter.performed_jobs.count)
|
18
|
-
assert(Time.now - start_time > (1 * sleep_time))
|
19
|
-
end
|
20
|
-
|
21
|
-
def test_wait
|
22
|
-
assert_equal(0, ActiveJob::Base.queue_adapter.enqueued_jobs.count)
|
23
|
-
|
24
|
-
start_time = Time.now
|
25
|
-
sleep_time = 2
|
26
|
-
threads = 3.times.map do |i|
|
27
|
-
Thread.new do
|
28
|
-
EnqueueWaitJob.perform_later(i, sleep_time)
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
threads.each {|thread| thread.join}
|
33
|
-
|
34
|
-
assert_equal(0, ActiveJob::Base.queue_adapter.enqueued_jobs.count)
|
35
|
-
assert_equal(threads.count, ActiveJob::Base.queue_adapter.performed_jobs.count)
|
36
|
-
assert(Time.now - start_time > (threads.count * sleep_time))
|
37
|
-
end
|
38
|
-
|
39
|
-
def test_wait_large_timeout
|
40
|
-
assert_equal(0, ActiveJob::Base.queue_adapter.enqueued_jobs.count)
|
41
|
-
|
42
|
-
start_time = Time.now
|
43
|
-
sleep_time = 2 * EnqueueWaitTimeoutJob.lock_acquire_timeout
|
44
|
-
threads = 3.times.map do |i|
|
45
|
-
Thread.new do
|
46
|
-
EnqueueWaitTimeoutJob.perform_later(i, sleep_time)
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
threads.each {|thread| thread.join}
|
51
|
-
|
52
|
-
assert_equal(0, ActiveJob::Base.queue_adapter.enqueued_jobs.count)
|
53
|
-
assert_equal(1, ActiveJob::Base.queue_adapter.performed_jobs.count)
|
54
|
-
assert(Time.now - start_time > (1 * sleep_time))
|
55
|
-
end
|
56
|
-
|
57
|
-
def test_wait_timeout
|
58
|
-
assert_equal(0, ActiveJob::Base.queue_adapter.enqueued_jobs.count)
|
59
|
-
|
60
|
-
start_time = Time.now
|
61
|
-
sleep_time = 0.2 * EnqueueWaitLargeTimeoutJob.lock_acquire_timeout
|
62
|
-
threads = 3.times.map do |i|
|
63
|
-
Thread.new do
|
64
|
-
EnqueueWaitLargeTimeoutJob.perform_later(i, sleep_time)
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
threads.each {|thread| thread.join}
|
69
|
-
|
70
|
-
assert_equal(0, ActiveJob::Base.queue_adapter.enqueued_jobs.count)
|
71
|
-
assert_equal(threads.count, ActiveJob::Base.queue_adapter.performed_jobs.count)
|
72
|
-
assert(Time.now - start_time > (threads.count * sleep_time))
|
73
|
-
end
|
74
|
-
end
|
@@ -1,16 +0,0 @@
|
|
1
|
-
class EnqueueWaitLargeTimeoutJob < ActiveJob::Base
|
2
|
-
include ActiveJob::Locking::Enqueue
|
3
|
-
|
4
|
-
# Wait for 10 seconds to get a lock
|
5
|
-
self.lock_acquire_timeout = 10
|
6
|
-
|
7
|
-
# We want the job ids to be all the same for testing
|
8
|
-
def lock_key
|
9
|
-
self.class.name
|
10
|
-
end
|
11
|
-
|
12
|
-
# Pass in index so we can distinguish different jobs
|
13
|
-
def perform(index, sleep_time)
|
14
|
-
sleep(sleep_time)
|
15
|
-
end
|
16
|
-
end
|
@@ -1,16 +0,0 @@
|
|
1
|
-
class EnqueueWaitTimeoutJob < ActiveJob::Base
|
2
|
-
include ActiveJob::Locking::Enqueue
|
3
|
-
|
4
|
-
# Wait for 1 second to get a lock
|
5
|
-
self.lock_acquire_timeout = 1
|
6
|
-
|
7
|
-
# We want the job ids to be all the same for testing
|
8
|
-
def lock_key
|
9
|
-
self.class.name
|
10
|
-
end
|
11
|
-
|
12
|
-
# Pass in index so we can distinguish different jobs
|
13
|
-
def perform(index, sleep_time)
|
14
|
-
sleep(sleep_time)
|
15
|
-
end
|
16
|
-
end
|
@@ -1,16 +0,0 @@
|
|
1
|
-
class PerformSeriallyLargeTimeoutJob < ActiveJob::Base
|
2
|
-
include ActiveJob::Locking::Enqueue
|
3
|
-
|
4
|
-
# Wait for 10 seconds to get a lock
|
5
|
-
self.lock_acquire_timeout = 10
|
6
|
-
|
7
|
-
# We want the job ids to be all the same for testing
|
8
|
-
def lock_key
|
9
|
-
self.class.name
|
10
|
-
end
|
11
|
-
|
12
|
-
# Pass in index so we can distinguish different jobs
|
13
|
-
def perform(index, sleep_time)
|
14
|
-
sleep(sleep_time)
|
15
|
-
end
|
16
|
-
end
|
data/test/perform_tests.rb
DELETED
@@ -1,37 +0,0 @@
|
|
1
|
-
require File.expand_path('../test_helper', __FILE__)
|
2
|
-
|
3
|
-
module PerformTests
|
4
|
-
def test_serialize
|
5
|
-
start_time = Time.now
|
6
|
-
sleep_time = 2
|
7
|
-
threads = 3.times.map do |i|
|
8
|
-
Thread.new do
|
9
|
-
PerformSeriallyJob.perform_later(i, sleep_time)
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
threads.each {|thread| thread.join}
|
14
|
-
|
15
|
-
assert_equal(0, ActiveJob::Base.queue_adapter.enqueued_jobs.count)
|
16
|
-
assert_equal(threads.count, ActiveJob::Base.queue_adapter.performed_jobs.count)
|
17
|
-
assert(Time.now - start_time > (threads.count * sleep_time))
|
18
|
-
end
|
19
|
-
|
20
|
-
def test_wait_large_timeout
|
21
|
-
assert_equal(0, ActiveJob::Base.queue_adapter.enqueued_jobs.count)
|
22
|
-
|
23
|
-
start_time = Time.now
|
24
|
-
sleep_time = 2 * EnqueueWaitTimeoutJob.lock_acquire_timeout
|
25
|
-
threads = 3.times.map do |i|
|
26
|
-
Thread.new do
|
27
|
-
EnqueueWaitTimeoutJob.perform_later(i, sleep_time)
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
threads.each {|thread| thread.join}
|
32
|
-
|
33
|
-
assert_equal(0, ActiveJob::Base.queue_adapter.enqueued_jobs.count)
|
34
|
-
assert_equal(1, ActiveJob::Base.queue_adapter.performed_jobs.count)
|
35
|
-
assert(Time.now - start_time > (1 * sleep_time))
|
36
|
-
end
|
37
|
-
end
|
data/test/test_enqueue_memory.rb
DELETED
@@ -1,45 +0,0 @@
|
|
1
|
-
require_relative('./enqueue_tests')
|
2
|
-
|
3
|
-
class EnqueueMemoryTest < MiniTest::Test
|
4
|
-
include EnqueueTests
|
5
|
-
|
6
|
-
def setup
|
7
|
-
ActiveJob::Base.queue_adapter = :test
|
8
|
-
ActiveJob::Base.queue_adapter.perform_enqueued_jobs = true
|
9
|
-
ActiveJob::Locking.options.adapter = ActiveJob::Locking::Adapters::Memory
|
10
|
-
end
|
11
|
-
|
12
|
-
def test_enqueue_one
|
13
|
-
ActiveJob::Base.queue_adapter.perform_enqueued_jobs = false
|
14
|
-
ActiveJob::Locking.options.adapter = ActiveJob::Locking::Adapters::Memory
|
15
|
-
|
16
|
-
ActiveJob::Base.queue_adapter.perform_enqueued_jobs = false
|
17
|
-
assert_equal(0, ActiveJob::Base.queue_adapter.enqueued_jobs.count)
|
18
|
-
|
19
|
-
sleep_time = 2
|
20
|
-
threads = 3.times.map do |i|
|
21
|
-
Thread.new do
|
22
|
-
EnqueueDropJob.perform_later(i, sleep_time)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
threads.each {|thread| thread.join}
|
27
|
-
assert_equal(1, ActiveJob::Base.queue_adapter.enqueued_jobs.count)
|
28
|
-
end
|
29
|
-
|
30
|
-
def test_perform_one
|
31
|
-
ActiveJob::Locking.options.adapter = ActiveJob::Locking::Adapters::Memory
|
32
|
-
|
33
|
-
assert_equal(0, ActiveJob::Base.queue_adapter.performed_jobs.count)
|
34
|
-
|
35
|
-
sleep_time = 1
|
36
|
-
threads = 3.times.map do |i|
|
37
|
-
Thread.new do
|
38
|
-
EnqueueDropJob.perform_later(i, sleep_time)
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
threads.each {|thread| thread.join}
|
43
|
-
assert_equal(1, ActiveJob::Base.queue_adapter.performed_jobs.count)
|
44
|
-
end
|
45
|
-
end
|
data/test/test_perform_memory.rb
DELETED
@@ -1,14 +0,0 @@
|
|
1
|
-
require_relative('./perform_tests')
|
2
|
-
|
3
|
-
class PerformMemory < MiniTest::Test
|
4
|
-
include PerformTests
|
5
|
-
|
6
|
-
def setup
|
7
|
-
redis_reset
|
8
|
-
|
9
|
-
ActiveJob::Base.queue_adapter = :test
|
10
|
-
ActiveJob::Base.queue_adapter.perform_enqueued_jobs = true
|
11
|
-
ActiveJob::Locking.options.adapter = ActiveJob::Locking::Adapters::Memory
|
12
|
-
ActiveJob::Locking.options.hosts = Redlock::Client::DEFAULT_REDIS_URLS
|
13
|
-
end
|
14
|
-
end
|