resque-unique_at_runtime 2.0.4 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +2 -0
- data/.rubocop_todo.yml +75 -0
- data/Gemfile +10 -6
- data/README.md +17 -10
- data/Rakefile +6 -4
- data/lib/resque-unique_at_runtime.rb +58 -75
- data/lib/resque/plugins/unique_at_runtime.rb +111 -0
- data/lib/resque/unique_at_runtime/configuration.rb +47 -0
- data/lib/resque/unique_at_runtime/resque_ext/resque.rb +9 -0
- data/lib/resque/unique_at_runtime/version.rb +7 -0
- data/resque-unique_at_runtime.gemspec +52 -41
- metadata +118 -19
- data/lib/resque-unique_at_runtime/version.rb +0 -7
- data/spec/lib/unique_at_runtime_spec.rb +0 -180
- data/spec/spec_helper.rb +0 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 645ac4f759c2b0721d782071985fdec3d14de968eeef88ae760c0a6e1deb0c67
|
4
|
+
data.tar.gz: f2a99e565e17ae87b290b8a834cfb9f6d5d9474fa7ae158eba361344f33c7850
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: acbfec52b562d31dc543fa4de471700d485cc3654a0ab7813e07a68f029f7d6e43e953e3de849cca9f39f62359ea29b216b2dec3d0e9b3c8a1e9264c595ac777
|
7
|
+
data.tar.gz: 7941f8e4a0eabd5a222fd832b46f32f73b52b14ec4a94aa842ba948f26037cbc8b1d1c3e115dad91beba494aa40dd925aa26a8f598cb57e88227642ba337d68e
|
data/.rubocop.yml
ADDED
data/.rubocop_todo.yml
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
# This configuration was generated by
|
2
|
+
# `rubocop --auto-gen-config`
|
3
|
+
# on 2018-11-07 04:06:03 -0800 using RuboCop version 0.59.0.
|
4
|
+
# The point is for the user to remove these configuration records
|
5
|
+
# one by one as the offenses are removed from the code base.
|
6
|
+
# Note that changes in the inspected code, or installation of new
|
7
|
+
# versions of RuboCop, may require this file to be generated again.
|
8
|
+
|
9
|
+
# Offense count: 1
|
10
|
+
# Configuration parameters: Include.
|
11
|
+
# Include: **/*.gemspec
|
12
|
+
Gemspec/RequiredRubyVersion:
|
13
|
+
Exclude:
|
14
|
+
- 'resque-unique_at_runtime.gemspec'
|
15
|
+
|
16
|
+
# Offense count: 1
|
17
|
+
Metrics/AbcSize:
|
18
|
+
Max: 17
|
19
|
+
|
20
|
+
# Offense count: 3
|
21
|
+
# Configuration parameters: CountComments, ExcludedMethods.
|
22
|
+
# ExcludedMethods: refine
|
23
|
+
Metrics/BlockLength:
|
24
|
+
Max: 102
|
25
|
+
|
26
|
+
# Offense count: 2
|
27
|
+
# Configuration parameters: ExpectMatchingDefinition, Regex, IgnoreExecutableScripts, AllowedAcronyms.
|
28
|
+
# AllowedAcronyms: CLI, DSL, ACL, API, ASCII, CPU, CSS, DNS, EOF, GUID, HTML, HTTP, HTTPS, ID, IP, JSON, LHS, QPS, RAM, RHS, RPC, SLA, SMTP, SQL, SSH, TCP, TLS, TTL, UDP, UI, UID, UUID, URI, URL, UTF8, VM, XML, XMPP, XSRF, XSS
|
29
|
+
Naming/FileName:
|
30
|
+
Exclude:
|
31
|
+
- 'lib/resque-unique_at_runtime.rb'
|
32
|
+
- 'resque-unique_at_runtime.gemspec'
|
33
|
+
|
34
|
+
# Offense count: 1
|
35
|
+
# Configuration parameters: EnforcedStyle.
|
36
|
+
# SupportedStyles: lowercase, uppercase
|
37
|
+
Naming/HeredocDelimiterCase:
|
38
|
+
Exclude:
|
39
|
+
- 'resque-unique_at_runtime.gemspec'
|
40
|
+
|
41
|
+
# Offense count: 1
|
42
|
+
# Configuration parameters: MinNameLength, AllowNamesEndingInNumbers, AllowedNames, ForbiddenNames.
|
43
|
+
# AllowedNames: io, id, to, by, on, in, at, ip, db
|
44
|
+
Naming/UncommunicativeMethodParamName:
|
45
|
+
Exclude:
|
46
|
+
- 'lib/resque/plugins/unique_at_runtime.rb'
|
47
|
+
|
48
|
+
# Offense count: 1
|
49
|
+
# Configuration parameters: AllowedChars.
|
50
|
+
Style/AsciiComments:
|
51
|
+
Exclude:
|
52
|
+
- 'lib/resque/plugins/unique_at_runtime.rb'
|
53
|
+
|
54
|
+
# Offense count: 4
|
55
|
+
Style/Documentation:
|
56
|
+
Exclude:
|
57
|
+
- 'spec/**/*'
|
58
|
+
- 'test/**/*'
|
59
|
+
- 'lib/resque-unique_at_runtime.rb'
|
60
|
+
- 'lib/resque/plugins/unique_at_runtime.rb'
|
61
|
+
- 'lib/resque/unique_at_runtime/configuration.rb'
|
62
|
+
- 'lib/resque/unique_at_runtime/resque_ext/resque.rb'
|
63
|
+
|
64
|
+
# Offense count: 1
|
65
|
+
# Cop supports --auto-correct.
|
66
|
+
# Configuration parameters: AllowAsExpressionSeparator.
|
67
|
+
Style/Semicolon:
|
68
|
+
Exclude:
|
69
|
+
- 'spec/lib/unique_at_runtime_spec.rb'
|
70
|
+
|
71
|
+
# Offense count: 26
|
72
|
+
# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
|
73
|
+
# URISchemes: http, https
|
74
|
+
Metrics/LineLength:
|
75
|
+
Max: 120
|
data/Gemfile
CHANGED
@@ -1,15 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
source 'https://rubygems.org'
|
2
4
|
|
3
5
|
git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
|
4
6
|
|
5
7
|
group :test do
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
8
|
+
unless ENV['TRAVIS']
|
9
|
+
gem 'byebug', '~> 10', platform: :mri, require: false
|
10
|
+
gem 'pry', '~> 0', platform: :mri, require: false
|
11
|
+
gem 'pry-byebug', '~> 3', platform: :mri, require: false
|
12
|
+
end
|
13
|
+
gem 'rubocop', '~> 0.60.0'
|
14
|
+
gem 'rubocop-rspec', '~> 1.30.0'
|
11
15
|
gem 'simplecov', '~> 0', require: false
|
12
16
|
end
|
13
17
|
|
14
|
-
# Specify your gem's dependencies in
|
18
|
+
# Specify your gem's dependencies in unique_at_runtime.gemspec
|
15
19
|
gemspec
|
data/README.md
CHANGED
@@ -63,7 +63,7 @@ Or install it yourself as:
|
|
63
63
|
require 'resque-unique_at_runtime'
|
64
64
|
|
65
65
|
class StrictlySerialJob
|
66
|
-
|
66
|
+
include Resque::Plugins::UniqueAtRuntime
|
67
67
|
|
68
68
|
@queue = :serial_work
|
69
69
|
|
@@ -82,7 +82,7 @@ method.
|
|
82
82
|
require 'resque-unique_at_runtime'
|
83
83
|
|
84
84
|
class StrictlySerialJob
|
85
|
-
|
85
|
+
include Resque::Plugins::UniqueAtRuntime
|
86
86
|
|
87
87
|
@queue = :serial_work
|
88
88
|
|
@@ -171,7 +171,7 @@ for its job (data x, data y, data z).
|
|
171
171
|
|
172
172
|
#### Example #4 -- Requeue interval
|
173
173
|
|
174
|
-
The behavior when multiple jobs exist in a queue protected by resque-unique_at_runtime
|
174
|
+
The behavior when multiple jobs exist in a queue protected by `resque-unique_at_runtime`
|
175
175
|
is for one job to be worked, while the other is continuously dequeued and
|
176
176
|
requeued until the first job is finished. This can result in that worker
|
177
177
|
process pegging a CPU/core on a worker server. To guard against this, the
|
@@ -185,7 +185,7 @@ in your job like so:
|
|
185
185
|
require 'resque-unique_at_runtime'
|
186
186
|
|
187
187
|
class StrictlySerialJob
|
188
|
-
|
188
|
+
include Resque::Plugins::UniqueAtRuntime
|
189
189
|
|
190
190
|
@queue = :serial_work
|
191
191
|
@runtime_requeue_interval = 5 # sleep for 5 seconds before requeueing
|
@@ -195,18 +195,26 @@ in your job like so:
|
|
195
195
|
end
|
196
196
|
end
|
197
197
|
|
198
|
+
#### Example #5 -- Check if a job is running
|
199
|
+
|
200
|
+
`resque-unique_at_runtime` extends `Resque` with a new method `running?`.
|
201
|
+
|
202
|
+
It can tell you if a job with a specific signature is running, based on the
|
203
|
+
presence of the runtime uniqueness key.
|
204
|
+
|
205
|
+
Caveat: It can be difficult to get the signature right, especially if you have
|
206
|
+
tools that enhance job signatures with options.
|
207
|
+
|
198
208
|
## Contributing
|
199
209
|
|
210
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/pboling/resque-unique_at_runtime. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
211
|
+
|
200
212
|
1. Fork it
|
201
213
|
2. Create your feature branch (`git checkout -b my-new-feature`)
|
202
214
|
3. Commit your changes (`git commit -am 'Added some feature'`)
|
203
215
|
4. Push to the branch (`git push origin my-new-feature`)
|
204
216
|
5. Create new Pull Request
|
205
217
|
|
206
|
-
## Contributing
|
207
|
-
|
208
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/pboling/resque-unique_at_runtime. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
209
|
-
|
210
218
|
## Code of Conduct
|
211
219
|
|
212
220
|
Everyone interacting in the Resque::Plugins::UniqueAtRuntime project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/pboling/resque-unique_at_runtime/blob/master/CODE_OF_CONDUCT.md).
|
@@ -226,10 +234,9 @@ dependency on this gem using the [Pessimistic Version Constraint][pvc] with two
|
|
226
234
|
For example:
|
227
235
|
|
228
236
|
```ruby
|
229
|
-
spec.add_dependency 'resque-unique_at_runtime', '~>
|
237
|
+
spec.add_dependency 'resque-unique_at_runtime', '~> 1.0'
|
230
238
|
```
|
231
239
|
|
232
|
-
|
233
240
|
## License
|
234
241
|
|
235
242
|
* Copyright (c) 2012 Jonathan R. Wallace
|
data/Rakefile
CHANGED
@@ -1,8 +1,10 @@
|
|
1
1
|
#!/usr/bin/env rake
|
2
|
-
|
3
|
-
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'bundler/gem_tasks'
|
5
|
+
require 'rspec/core/rake_task'
|
4
6
|
|
5
7
|
RSpec::Core::RakeTask.new
|
6
8
|
|
7
|
-
task :
|
8
|
-
task :
|
9
|
+
task default: :spec
|
10
|
+
task test: :spec
|
@@ -1,91 +1,74 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
module Plugins
|
5
|
-
module UniqueAtRuntime
|
6
|
-
LOCK_TIMEOUT = 60 * 60 * 24 * 5
|
7
|
-
REQUEUE_INTERVAL = 1
|
8
|
-
|
9
|
-
def runtime_lock_timeout_at(now)
|
10
|
-
now + runtime_lock_timeout + 1
|
11
|
-
end
|
3
|
+
require 'resque/unique_at_runtime/version'
|
12
4
|
|
13
|
-
|
14
|
-
|
15
|
-
end
|
5
|
+
# Ruby Std Lib
|
6
|
+
require 'digest/md5'
|
16
7
|
|
17
|
-
|
18
|
-
|
19
|
-
|
8
|
+
# External Gems
|
9
|
+
require 'colorized_string'
|
10
|
+
require 'resque'
|
20
11
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
"resque-unique_at_runtime:#{@queue}"
|
26
|
-
end
|
12
|
+
# This Gem
|
13
|
+
require 'resque/plugins/unique_at_runtime'
|
14
|
+
require 'resque/unique_at_runtime/resque_ext/resque'
|
15
|
+
require 'resque/unique_at_runtime/configuration'
|
27
16
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
17
|
+
# See lib/resque/plugins/unique_at_runtime.rb for the actual plugin
|
18
|
+
#
|
19
|
+
# This is not that ^. Rather, it is an API used by the plugin or as tools by a
|
20
|
+
# developer. These methods are not intended to be included/extended into
|
21
|
+
# Resque, Resque::Job, or Resque::Queue.
|
22
|
+
module Resque
|
23
|
+
module UniqueAtRuntime
|
24
|
+
PLUGIN_TAG = (ColorizedString['[R-UAR] '].blue).freeze
|
36
25
|
|
37
|
-
|
26
|
+
def runtime_unique_log(message, config_proxy = nil)
|
27
|
+
config_proxy ||= uniqueness_configuration
|
28
|
+
config_proxy.unique_logger&.send(config_proxy.unique_log_level, message)
|
29
|
+
end
|
38
30
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
return key
|
44
|
-
end
|
31
|
+
def runtime_unique_debug(message, config_proxy = nil)
|
32
|
+
config_proxy ||= uniqueness_configuration
|
33
|
+
config_proxy.unique_logger&.debug("#{PLUGIN_TAG}#{message}") if config_proxy.debug_mode
|
34
|
+
end
|
45
35
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
36
|
+
# There are times when the class will need access to the configuration object,
|
37
|
+
# such as to override it per instance method
|
38
|
+
def uniq_config
|
39
|
+
@uniqueness_configuration
|
40
|
+
end
|
51
41
|
|
52
|
-
|
53
|
-
|
54
|
-
|
42
|
+
# For per-class config with a block
|
43
|
+
def uniqueness_configure
|
44
|
+
@uniqueness_configuration ||= Configuration.new
|
45
|
+
yield(@uniqueness_configuration)
|
46
|
+
end
|
55
47
|
|
56
|
-
|
57
|
-
|
58
|
-
|
48
|
+
#### CONFIG ####
|
49
|
+
class << self
|
50
|
+
attr_accessor :uniqueness_configuration
|
51
|
+
end
|
52
|
+
def uniqueness_config_reset(config = Configuration.new)
|
53
|
+
@uniqueness_configuration = config
|
54
|
+
end
|
59
55
|
|
60
|
-
|
61
|
-
|
56
|
+
def uniqueness_log_level
|
57
|
+
@uniqueness_configuration.log_level
|
58
|
+
end
|
62
59
|
|
63
|
-
|
64
|
-
|
60
|
+
def uniqueness_log_level=(log_level)
|
61
|
+
@uniqueness_configuration.log_level = log_level
|
62
|
+
end
|
65
63
|
|
66
|
-
|
67
|
-
raise Resque::Job::DontPerform
|
68
|
-
else
|
69
|
-
puts "will perform"
|
70
|
-
true
|
71
|
-
end
|
72
|
-
end
|
64
|
+
self.uniqueness_configuration = Configuration.new # setup defaults
|
73
65
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
# There may be scenarios where the around_perform's ensure unlock
|
83
|
-
# duplicates the on_failure unlock, but that's a small price to pay for
|
84
|
-
# uniqueness.
|
85
|
-
def on_failure_unlock_runtime(*args)
|
86
|
-
puts "resque-unique_at_runtime: on failure unlock" if ENV['RESQUE_DEBUG']
|
87
|
-
unlock_queue(*args)
|
88
|
-
end
|
89
|
-
end
|
66
|
+
module_function(:runtime_unique_log,
|
67
|
+
:runtime_unique_debug,
|
68
|
+
:uniq_config,
|
69
|
+
:uniqueness_configure,
|
70
|
+
:uniqueness_config_reset,
|
71
|
+
:uniqueness_log_level,
|
72
|
+
:uniqueness_log_level=)
|
90
73
|
end
|
91
74
|
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Resque
|
4
|
+
module Plugins
|
5
|
+
# If you want your job to support uniqueness at runtime, simply include
|
6
|
+
# this module into your job class.
|
7
|
+
#
|
8
|
+
# class RunAlone
|
9
|
+
# @queue = :run_alone
|
10
|
+
# include Resque::Plugins::UniqueAtRuntime
|
11
|
+
#
|
12
|
+
# def self.perform(arg1, arg2)
|
13
|
+
# alone_stuff
|
14
|
+
# end
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
module UniqueAtRuntime
|
18
|
+
def self.included(base)
|
19
|
+
base.extend ClassMethods
|
20
|
+
end
|
21
|
+
|
22
|
+
module ClassMethods
|
23
|
+
def runtime_lock_timeout_at(now)
|
24
|
+
now + runtime_lock_timeout + 1
|
25
|
+
end
|
26
|
+
|
27
|
+
def runtime_lock_timeout
|
28
|
+
instance_variable_get(:@runtime_lock_timeout) || Resque::UniqueAtRuntime.uniq_config&.lock_timeout
|
29
|
+
end
|
30
|
+
|
31
|
+
def runtime_requeue_interval
|
32
|
+
instance_variable_get(:@runtime_requeue_interval) || Resque::UniqueAtRuntime.uniq_config&.requeue_interval
|
33
|
+
end
|
34
|
+
|
35
|
+
# Overwrite this method to uniquely identify which mutex should be used
|
36
|
+
# for a resque worker.
|
37
|
+
def unique_at_runtime_redis_key(*_)
|
38
|
+
Resque::UniqueAtRuntime.runtime_unique_debug("getting key for #{@queue}!")
|
39
|
+
"#{unique_at_runtime_key_base}:#{@queue}"
|
40
|
+
end
|
41
|
+
|
42
|
+
# returns true if the job signature can be locked (is not currently locked)
|
43
|
+
def can_lock_queue?(*args)
|
44
|
+
!queue_locked?(*args)
|
45
|
+
end
|
46
|
+
|
47
|
+
# returns the locking key if locked, otherwise false
|
48
|
+
def queue_locked?(*args)
|
49
|
+
now = Time.now.to_i
|
50
|
+
key = unique_at_runtime_redis_key(*args)
|
51
|
+
timeout = runtime_lock_timeout_at(now)
|
52
|
+
|
53
|
+
Resque::UniqueAtRuntime.runtime_unique_debug("attempting to lock queue with #{key}")
|
54
|
+
|
55
|
+
# Per http://redis.io/commands/setnx
|
56
|
+
return false if Resque.redis.setnx(key, timeout)
|
57
|
+
return key if Resque.redis.get(key).to_i > now
|
58
|
+
return false if Resque.redis.getset(key, timeout).to_i <= now
|
59
|
+
|
60
|
+
key
|
61
|
+
end
|
62
|
+
|
63
|
+
def unlock_queue(*args)
|
64
|
+
key = unique_at_runtime_redis_key(*args)
|
65
|
+
Resque::UniqueAtRuntime.runtime_unique_debug("unlock queue with #{key}")
|
66
|
+
Resque.redis.del(key)
|
67
|
+
end
|
68
|
+
|
69
|
+
def reenqueue(*args)
|
70
|
+
Resque.enqueue(self, *args)
|
71
|
+
end
|
72
|
+
|
73
|
+
def before_perform_lock_runtime(*args)
|
74
|
+
if (key = queue_locked?(*args))
|
75
|
+
Resque::UniqueAtRuntime.runtime_unique_debug("failed to lock queue with #{key}")
|
76
|
+
|
77
|
+
# Sleep so the CPU's rest
|
78
|
+
sleep(runtime_requeue_interval)
|
79
|
+
|
80
|
+
# can't get the lock, so re-enqueue the task
|
81
|
+
reenqueue(*args)
|
82
|
+
|
83
|
+
# and don't perform
|
84
|
+
raise Resque::Job::DontPerform
|
85
|
+
else
|
86
|
+
Resque::UniqueAtRuntime.runtime_unique_debug('check passed will perform')
|
87
|
+
true
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def around_perform_unlock_runtime(*args)
|
92
|
+
yield
|
93
|
+
ensure
|
94
|
+
unlock_queue(*args)
|
95
|
+
end
|
96
|
+
|
97
|
+
# There may be scenarios where the around_perform's ensure unlock±
|
98
|
+
# duplicates the on_failure unlock, but that's a small price to pay for
|
99
|
+
# uniqueness.
|
100
|
+
def on_failure_unlock_runtime(*args)
|
101
|
+
Resque::UniqueAtRuntime.runtime_unique_debug('on failure unlock')
|
102
|
+
unlock_queue(*args)
|
103
|
+
end
|
104
|
+
|
105
|
+
def unique_at_runtime_key_base
|
106
|
+
instance_variable_get(:@unique_at_runtime_key_base) || Resque::UniqueAtRuntime.uniq_config&.unique_at_runtime_key_base
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'logger'
|
4
|
+
module Resque
|
5
|
+
module UniqueAtRuntime
|
6
|
+
class Configuration
|
7
|
+
DEFAULT_AT_RUNTIME_KEY_BASE = 'r-uae'
|
8
|
+
DEFAULT_LOCK_TIMEOUT = 60 * 60 * 24 * 5
|
9
|
+
DEFAULT_REQUEUE_INTERVAL = 1
|
10
|
+
|
11
|
+
attr_accessor :logger,
|
12
|
+
:log_level,
|
13
|
+
:unique_at_runtime_key_base,
|
14
|
+
:lock_timeout,
|
15
|
+
:requeue_interval,
|
16
|
+
:debug_mode
|
17
|
+
def initialize(**options)
|
18
|
+
@logger = options.key?(:logger) ? options[:logger] : Logger.new(STDOUT)
|
19
|
+
@log_level = options.key?(:log_level) ? options[:log_level] : :debug
|
20
|
+
@unique_at_runtime_key_base = options.key?(:unique_at_runtime_key_base) ? options[:unique_at_runtime_key_base] : DEFAULT_AT_RUNTIME_KEY_BASE
|
21
|
+
@lock_timeout = options.key?(:lock_timeout) ? options[:lock_timeout] : DEFAULT_LOCK_TIMEOUT
|
22
|
+
@requeue_interval = options.key?(:requeue_interval) ? options[:requeue_interval] : DEFAULT_REQUEUE_INTERVAL
|
23
|
+
env_debug = ENV['RESQUE_DEBUG']
|
24
|
+
@debug_mode = options.key?(:debug_mode) ? options[:debug_mode] : env_debug == 'true' || (env_debug.is_a?(String) && env_debug.match?(/runtime/))
|
25
|
+
end
|
26
|
+
|
27
|
+
def unique_logger
|
28
|
+
logger
|
29
|
+
end
|
30
|
+
|
31
|
+
def unique_log_level
|
32
|
+
log_level
|
33
|
+
end
|
34
|
+
|
35
|
+
def log(msg)
|
36
|
+
Resque::UniqueAtRuntime.runtime_unique_log(msg, self)
|
37
|
+
end
|
38
|
+
|
39
|
+
def to_hash
|
40
|
+
{
|
41
|
+
logger: logger,
|
42
|
+
log_level: log_level
|
43
|
+
}
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -1,43 +1,54 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
gem.add_dependency 'resque', '>= 1.2'
|
20
|
-
gem.add_development_dependency 'mock_redis'
|
21
|
-
gem.add_development_dependency 'rake'
|
22
|
-
gem.add_development_dependency 'rspec', '>= 3.0'
|
23
|
-
gem.add_development_dependency 'timecop'
|
24
|
-
|
25
|
-
gem.description = <<desc
|
26
|
-
Ensures that for a given queue, only one worker is working on a job at any given time.
|
27
|
-
|
28
|
-
Example:
|
29
|
-
|
30
|
-
require 'resque/plugins/unique_at_runtime'
|
31
|
-
|
32
|
-
class StrictlySerialJob
|
33
|
-
extend Resque::Plugins::UniqueAtRuntime
|
34
|
-
|
35
|
-
@queue = :serial_work
|
36
|
-
|
37
|
-
def self.perform
|
38
|
-
# only one at a time in this block, no parallelism allowed for this
|
39
|
-
# particular queue
|
40
|
-
end
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require File.expand_path('lib/resque/unique_at_runtime/version', __dir__)
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = 'resque-unique_at_runtime'
|
7
|
+
spec.version = Resque::UniqueAtRuntime::VERSION
|
8
|
+
spec.authors = ['Peter H. Boling', 'Jonathan R. Wallace']
|
9
|
+
spec.email = ['peter.boling@gmail.com', 'jonathan.wallace@gmail.com']
|
10
|
+
spec.license = 'MIT'
|
11
|
+
|
12
|
+
spec.summary = 'A resque plugin that ensures job uniqueness at runtime.'
|
13
|
+
spec.homepage = 'http://github.com/pboling/resque-unique_at_runtime'
|
14
|
+
spec.required_ruby_version = '>= 2.3'
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
17
|
+
f.match(%r{^(test|spec|features)/})
|
41
18
|
end
|
42
|
-
|
19
|
+
spec.require_paths = ['lib']
|
20
|
+
|
21
|
+
spec.add_runtime_dependency 'colorize', '~> 0.8'
|
22
|
+
spec.add_runtime_dependency 'resque', '>= 1.2'
|
23
|
+
|
24
|
+
spec.add_development_dependency 'fakeredis', '~> 0.7'
|
25
|
+
spec.add_development_dependency 'rake', '~> 12.3'
|
26
|
+
spec.add_development_dependency 'rspec', '>= 3.0'
|
27
|
+
spec.add_development_dependency 'rspec-block_is_expected', '~> 1.0'
|
28
|
+
spec.add_development_dependency 'rspec-stubbed_env', '~> 1.0'
|
29
|
+
spec.add_development_dependency 'timecop'
|
30
|
+
|
31
|
+
spec.add_development_dependency 'pry', '~> 0.11'
|
32
|
+
spec.add_development_dependency 'pry-byebug', '~> 3.6'
|
33
|
+
spec.add_development_dependency 'rubocop', '~> 0.60'
|
34
|
+
spec.add_development_dependency 'rubocop-rspec', '~> 1.30'
|
35
|
+
|
36
|
+
spec.description = <<~desc
|
37
|
+
Ensures that for a given queue, only one worker is working on a job at any given time.
|
38
|
+
|
39
|
+
Example:
|
40
|
+
|
41
|
+
require 'resque/plugins/unique_at_runtime'
|
42
|
+
|
43
|
+
class StrictlySerialJob
|
44
|
+
include Resque::Plugins::UniqueAtRuntime
|
45
|
+
|
46
|
+
@queue = :serial_work
|
47
|
+
|
48
|
+
def self.perform
|
49
|
+
# only one at a time in this block, no parallelism allowed for this
|
50
|
+
# particular queue
|
51
|
+
end
|
52
|
+
end
|
53
|
+
desc
|
43
54
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: resque-unique_at_runtime
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 3.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Peter H. Boling
|
@@ -9,8 +9,22 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2018-
|
12
|
+
date: 2018-11-08 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: colorize
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - "~>"
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '0.8'
|
21
|
+
type: :runtime
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - "~>"
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: '0.8'
|
14
28
|
- !ruby/object:Gem::Dependency
|
15
29
|
name: resque
|
16
30
|
requirement: !ruby/object:Gem::Requirement
|
@@ -26,33 +40,33 @@ dependencies:
|
|
26
40
|
- !ruby/object:Gem::Version
|
27
41
|
version: '1.2'
|
28
42
|
- !ruby/object:Gem::Dependency
|
29
|
-
name:
|
43
|
+
name: fakeredis
|
30
44
|
requirement: !ruby/object:Gem::Requirement
|
31
45
|
requirements:
|
32
|
-
- - "
|
46
|
+
- - "~>"
|
33
47
|
- !ruby/object:Gem::Version
|
34
|
-
version: '0'
|
48
|
+
version: '0.7'
|
35
49
|
type: :development
|
36
50
|
prerelease: false
|
37
51
|
version_requirements: !ruby/object:Gem::Requirement
|
38
52
|
requirements:
|
39
|
-
- - "
|
53
|
+
- - "~>"
|
40
54
|
- !ruby/object:Gem::Version
|
41
|
-
version: '0'
|
55
|
+
version: '0.7'
|
42
56
|
- !ruby/object:Gem::Dependency
|
43
57
|
name: rake
|
44
58
|
requirement: !ruby/object:Gem::Requirement
|
45
59
|
requirements:
|
46
|
-
- - "
|
60
|
+
- - "~>"
|
47
61
|
- !ruby/object:Gem::Version
|
48
|
-
version: '
|
62
|
+
version: '12.3'
|
49
63
|
type: :development
|
50
64
|
prerelease: false
|
51
65
|
version_requirements: !ruby/object:Gem::Requirement
|
52
66
|
requirements:
|
53
|
-
- - "
|
67
|
+
- - "~>"
|
54
68
|
- !ruby/object:Gem::Version
|
55
|
-
version: '
|
69
|
+
version: '12.3'
|
56
70
|
- !ruby/object:Gem::Dependency
|
57
71
|
name: rspec
|
58
72
|
requirement: !ruby/object:Gem::Requirement
|
@@ -67,6 +81,34 @@ dependencies:
|
|
67
81
|
- - ">="
|
68
82
|
- !ruby/object:Gem::Version
|
69
83
|
version: '3.0'
|
84
|
+
- !ruby/object:Gem::Dependency
|
85
|
+
name: rspec-block_is_expected
|
86
|
+
requirement: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - "~>"
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '1.0'
|
91
|
+
type: :development
|
92
|
+
prerelease: false
|
93
|
+
version_requirements: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - "~>"
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '1.0'
|
98
|
+
- !ruby/object:Gem::Dependency
|
99
|
+
name: rspec-stubbed_env
|
100
|
+
requirement: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - "~>"
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '1.0'
|
105
|
+
type: :development
|
106
|
+
prerelease: false
|
107
|
+
version_requirements: !ruby/object:Gem::Requirement
|
108
|
+
requirements:
|
109
|
+
- - "~>"
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '1.0'
|
70
112
|
- !ruby/object:Gem::Dependency
|
71
113
|
name: timecop
|
72
114
|
requirement: !ruby/object:Gem::Requirement
|
@@ -81,6 +123,62 @@ dependencies:
|
|
81
123
|
- - ">="
|
82
124
|
- !ruby/object:Gem::Version
|
83
125
|
version: '0'
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: pry
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
129
|
+
requirements:
|
130
|
+
- - "~>"
|
131
|
+
- !ruby/object:Gem::Version
|
132
|
+
version: '0.11'
|
133
|
+
type: :development
|
134
|
+
prerelease: false
|
135
|
+
version_requirements: !ruby/object:Gem::Requirement
|
136
|
+
requirements:
|
137
|
+
- - "~>"
|
138
|
+
- !ruby/object:Gem::Version
|
139
|
+
version: '0.11'
|
140
|
+
- !ruby/object:Gem::Dependency
|
141
|
+
name: pry-byebug
|
142
|
+
requirement: !ruby/object:Gem::Requirement
|
143
|
+
requirements:
|
144
|
+
- - "~>"
|
145
|
+
- !ruby/object:Gem::Version
|
146
|
+
version: '3.6'
|
147
|
+
type: :development
|
148
|
+
prerelease: false
|
149
|
+
version_requirements: !ruby/object:Gem::Requirement
|
150
|
+
requirements:
|
151
|
+
- - "~>"
|
152
|
+
- !ruby/object:Gem::Version
|
153
|
+
version: '3.6'
|
154
|
+
- !ruby/object:Gem::Dependency
|
155
|
+
name: rubocop
|
156
|
+
requirement: !ruby/object:Gem::Requirement
|
157
|
+
requirements:
|
158
|
+
- - "~>"
|
159
|
+
- !ruby/object:Gem::Version
|
160
|
+
version: '0.60'
|
161
|
+
type: :development
|
162
|
+
prerelease: false
|
163
|
+
version_requirements: !ruby/object:Gem::Requirement
|
164
|
+
requirements:
|
165
|
+
- - "~>"
|
166
|
+
- !ruby/object:Gem::Version
|
167
|
+
version: '0.60'
|
168
|
+
- !ruby/object:Gem::Dependency
|
169
|
+
name: rubocop-rspec
|
170
|
+
requirement: !ruby/object:Gem::Requirement
|
171
|
+
requirements:
|
172
|
+
- - "~>"
|
173
|
+
- !ruby/object:Gem::Version
|
174
|
+
version: '1.30'
|
175
|
+
type: :development
|
176
|
+
prerelease: false
|
177
|
+
version_requirements: !ruby/object:Gem::Requirement
|
178
|
+
requirements:
|
179
|
+
- - "~>"
|
180
|
+
- !ruby/object:Gem::Version
|
181
|
+
version: '1.30'
|
84
182
|
description: |
|
85
183
|
Ensures that for a given queue, only one worker is working on a job at any given time.
|
86
184
|
|
@@ -89,7 +187,7 @@ description: |
|
|
89
187
|
require 'resque/plugins/unique_at_runtime'
|
90
188
|
|
91
189
|
class StrictlySerialJob
|
92
|
-
|
190
|
+
include Resque::Plugins::UniqueAtRuntime
|
93
191
|
|
94
192
|
@queue = :serial_work
|
95
193
|
|
@@ -106,6 +204,8 @@ extensions: []
|
|
106
204
|
extra_rdoc_files: []
|
107
205
|
files:
|
108
206
|
- ".gitignore"
|
207
|
+
- ".rubocop.yml"
|
208
|
+
- ".rubocop_todo.yml"
|
109
209
|
- ".ruby-version"
|
110
210
|
- ".travis.yml"
|
111
211
|
- CODE_OF_CONDUCT.md
|
@@ -114,10 +214,11 @@ files:
|
|
114
214
|
- README.md
|
115
215
|
- Rakefile
|
116
216
|
- lib/resque-unique_at_runtime.rb
|
117
|
-
- lib/resque
|
217
|
+
- lib/resque/plugins/unique_at_runtime.rb
|
218
|
+
- lib/resque/unique_at_runtime/configuration.rb
|
219
|
+
- lib/resque/unique_at_runtime/resque_ext/resque.rb
|
220
|
+
- lib/resque/unique_at_runtime/version.rb
|
118
221
|
- resque-unique_at_runtime.gemspec
|
119
|
-
- spec/lib/unique_at_runtime_spec.rb
|
120
|
-
- spec/spec_helper.rb
|
121
222
|
homepage: http://github.com/pboling/resque-unique_at_runtime
|
122
223
|
licenses:
|
123
224
|
- MIT
|
@@ -130,7 +231,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
130
231
|
requirements:
|
131
232
|
- - ">="
|
132
233
|
- !ruby/object:Gem::Version
|
133
|
-
version:
|
234
|
+
version: '2.3'
|
134
235
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
135
236
|
requirements:
|
136
237
|
- - ">="
|
@@ -142,6 +243,4 @@ rubygems_version: 2.7.7
|
|
142
243
|
signing_key:
|
143
244
|
specification_version: 4
|
144
245
|
summary: A resque plugin that ensures job uniqueness at runtime.
|
145
|
-
test_files:
|
146
|
-
- spec/lib/unique_at_runtime_spec.rb
|
147
|
-
- spec/spec_helper.rb
|
246
|
+
test_files: []
|
@@ -1,180 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
class SerialJob
|
4
|
-
extend Resque::Plugins::UniqueAtRuntime
|
5
|
-
@queue = :serial_work
|
6
|
-
|
7
|
-
def self.perform(*args); end
|
8
|
-
end
|
9
|
-
|
10
|
-
class SerialJobWithCustomRedisKey
|
11
|
-
extend Resque::Plugins::UniqueAtRuntime
|
12
|
-
@queue = :serial_work
|
13
|
-
|
14
|
-
def self.unique_at_runtime_redis_key(account_id, *args)
|
15
|
-
"unique_at_runtime:#{@queue}:#{account_id}"
|
16
|
-
end
|
17
|
-
|
18
|
-
def self.perform(account_id, *args); end
|
19
|
-
end
|
20
|
-
|
21
|
-
describe Resque::Plugins::UniqueAtRuntime do
|
22
|
-
before do
|
23
|
-
Resque.redis.flushall
|
24
|
-
end
|
25
|
-
|
26
|
-
describe ".runtime_requeue_interval" do
|
27
|
-
it "should default to 5" do
|
28
|
-
expect(SerialJob.runtime_requeue_interval).to eql(1)
|
29
|
-
end
|
30
|
-
|
31
|
-
it "should be overridable with a class instance var" do
|
32
|
-
SerialJob.instance_variable_set(:@runtime_requeue_interval, 5)
|
33
|
-
expect(SerialJob.runtime_requeue_interval).to eql(5)
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
describe ".can_lock_queue?" do
|
38
|
-
it 'can lock a queue' do
|
39
|
-
expect(SerialJob.can_lock_queue?(:serial_work)).to eql(true)
|
40
|
-
end
|
41
|
-
|
42
|
-
it 'cannot lock an already locked queue' do
|
43
|
-
expect(SerialJob.can_lock_queue?(:serial_work)).to eql(true)
|
44
|
-
expect(SerialJob.can_lock_queue?(:serial_work)).to eql(false)
|
45
|
-
end
|
46
|
-
|
47
|
-
it 'cannot lock a queue with active lock' do
|
48
|
-
expect(SerialJob.can_lock_queue?(:serial_work)).to eql(true)
|
49
|
-
Timecop.travel(Date.today + 1) do
|
50
|
-
expect(SerialJob.can_lock_queue?(:serial_work)).to eql(false)
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
it 'can relock a queue with expired lock' do
|
55
|
-
expect(SerialJob.can_lock_queue?(:serial_work)).to eql(true)
|
56
|
-
|
57
|
-
Timecop.travel(Date.today + 10) do
|
58
|
-
expect(SerialJob.can_lock_queue?(:serial_work)).to eql(true)
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
it 'solves race condition with getset' do
|
63
|
-
expect(SerialJob.can_lock_queue?(:serial_work)).to eql(true)
|
64
|
-
|
65
|
-
Timecop.travel(Date.today + 10) do
|
66
|
-
threads = (1..10).to_a.map {
|
67
|
-
Thread.new {
|
68
|
-
Thread.current[:locked] = SerialJob.can_lock_queue?(:serial_work)
|
69
|
-
}
|
70
|
-
}
|
71
|
-
|
72
|
-
# Only one worker should acquire lock
|
73
|
-
locks = threads.map {|t| t.join; t[:locked] }
|
74
|
-
expect(locks.count(true)).to eql(1)
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
describe ".perform" do
|
80
|
-
before do
|
81
|
-
SerialJob.instance_variable_set(:@runtime_requeue_interval, 0)
|
82
|
-
end
|
83
|
-
|
84
|
-
describe "using the default redis key" do
|
85
|
-
it 'should lock and unlock the queue' do
|
86
|
-
job = Resque::Job.new(:serial_work, { 'class' => 'SerialJob', 'args' => %w[account_one job_one] })
|
87
|
-
|
88
|
-
# job is the first SerialJob to run so it can lock the queue and perform
|
89
|
-
expect(SerialJob).to receive(:queue_locked?).and_return(false)
|
90
|
-
|
91
|
-
# but it should also clean up after itself
|
92
|
-
expect(SerialJob).to receive(:unlock_queue)
|
93
|
-
|
94
|
-
job.perform
|
95
|
-
end
|
96
|
-
|
97
|
-
it 'should clean up lock even with catastrophic job failure' do
|
98
|
-
job = Resque::Job.new(:serial_work, { 'class' => 'SerialJob', 'args' => %w[account_one job_one] })
|
99
|
-
|
100
|
-
# job is the first SerialJob to run so it can lock the queue and perform
|
101
|
-
expect(SerialJob).to receive(:queue_locked?).and_return(false)
|
102
|
-
|
103
|
-
# but we have a catastrophic job failure
|
104
|
-
expect(SerialJob).to receive(:perform).and_raise(Exception)
|
105
|
-
|
106
|
-
# and still it should clean up after itself
|
107
|
-
expect(SerialJob).to receive(:unlock_queue).at_least(1).times
|
108
|
-
|
109
|
-
# unfortunately, the job will be lost but resque doesn't guarantee jobs
|
110
|
-
# aren't lost
|
111
|
-
expect { job.perform }.to raise_error(Exception)
|
112
|
-
end
|
113
|
-
|
114
|
-
it 'should place self at the end of the queue if unable to acquire the lock' do
|
115
|
-
job1_payload = %w[account_one job_one]
|
116
|
-
job2_payload = %w[account_one job_two]
|
117
|
-
Resque::Job.create(:serial_work, 'SerialJob', job1_payload)
|
118
|
-
Resque::Job.create(:serial_work, 'SerialJob', job2_payload)
|
119
|
-
|
120
|
-
expect(SerialJob).to receive(:queue_locked?).and_return(true)
|
121
|
-
|
122
|
-
# perform returns false when DontPerform exception is raised in
|
123
|
-
# before_perform callback
|
124
|
-
job1 = Resque.reserve(:serial_work)
|
125
|
-
expect(job1.perform).to eql(false)
|
126
|
-
|
127
|
-
first_queue_element = Resque.reserve(:serial_work)
|
128
|
-
expect(first_queue_element.payload["args"]).to eql([job2_payload])
|
129
|
-
end
|
130
|
-
end
|
131
|
-
|
132
|
-
describe "with a custom unique_at_runtime_redis_key" do
|
133
|
-
it 'should lock and unlock the queue' do
|
134
|
-
job = Resque::Job.new(:serial_work, { 'class' => 'SerialJobWithCustomRedisKey', 'args' => %w[account_one job_one] })
|
135
|
-
|
136
|
-
# job is the first SerialJobWithCustomRedisKey to run so it can lock the queue and perform
|
137
|
-
expect(SerialJobWithCustomRedisKey).to receive(:queue_locked?).and_return(false)
|
138
|
-
|
139
|
-
# but it should also clean up after itself
|
140
|
-
expect(SerialJobWithCustomRedisKey).to receive(:unlock_queue)
|
141
|
-
|
142
|
-
job.perform
|
143
|
-
end
|
144
|
-
|
145
|
-
it 'should clean up lock even with catastrophic job failure' do
|
146
|
-
job = Resque::Job.new(:serial_work, { 'class' => 'SerialJobWithCustomRedisKey', 'args' => %w[account_one job_one] })
|
147
|
-
|
148
|
-
# job is the first SerialJobWithCustomRedisKey to run so it can lock the queue and perform
|
149
|
-
expect(SerialJobWithCustomRedisKey).to receive(:queue_locked?).and_return(false)
|
150
|
-
|
151
|
-
# but we have a catastrophic job failure
|
152
|
-
expect(SerialJobWithCustomRedisKey).to receive(:perform).and_raise(Exception)
|
153
|
-
|
154
|
-
# and still it should clean up after itself
|
155
|
-
expect(SerialJobWithCustomRedisKey).to receive(:unlock_queue).at_least(1).times
|
156
|
-
|
157
|
-
# unfortunately, the job will be lost but resque doesn't guarantee jobs
|
158
|
-
# aren't lost
|
159
|
-
expect { job.perform }.to raise_error(Exception)
|
160
|
-
end
|
161
|
-
|
162
|
-
it 'should place self at the end of the queue if unable to acquire the lock' do
|
163
|
-
job1_payload = %w[account_one job_one]
|
164
|
-
job2_payload = %w[account_one job_two]
|
165
|
-
Resque::Job.create(:serial_work, 'SerialJobWithCustomRedisKey', job1_payload)
|
166
|
-
Resque::Job.create(:serial_work, 'SerialJobWithCustomRedisKey', job2_payload)
|
167
|
-
|
168
|
-
expect(SerialJobWithCustomRedisKey).to receive(:queue_locked?).and_return(true)
|
169
|
-
|
170
|
-
# perform returns false when DontPerform exception is raised in
|
171
|
-
# before_perform callback
|
172
|
-
job1 = Resque.reserve(:serial_work)
|
173
|
-
expect(job1.perform).to eql(false)
|
174
|
-
|
175
|
-
first_queue_element = Resque.reserve(:serial_work)
|
176
|
-
expect(first_queue_element.payload["args"]).to eql([job2_payload])
|
177
|
-
end
|
178
|
-
end
|
179
|
-
end
|
180
|
-
end
|
data/spec/spec_helper.rb
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
require 'rspec'
|
2
|
-
|
3
|
-
require 'mock_redis'
|
4
|
-
require 'resque'
|
5
|
-
require 'timecop'
|
6
|
-
|
7
|
-
require 'byebug' if RbConfig::CONFIG['RUBY_INSTALL_NAME'] == 'ruby'
|
8
|
-
|
9
|
-
require 'simplecov'
|
10
|
-
SimpleCov.start
|
11
|
-
|
12
|
-
# This gem
|
13
|
-
require 'resque-unique_at_runtime'
|
14
|
-
|
15
|
-
RSpec.configure do |config|
|
16
|
-
config.before(:suite) do
|
17
|
-
Resque.redis = MockRedis.new
|
18
|
-
end
|
19
|
-
end
|