activejob-locking 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|