sidekiq 2.15.1 → 4.2.10

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of sidekiq might be problematic. Click here for more details.

Files changed (187) hide show
  1. checksums.yaml +7 -0
  2. data/.github/contributing.md +32 -0
  3. data/.github/issue_template.md +9 -0
  4. data/.gitignore +1 -0
  5. data/.travis.yml +16 -17
  6. data/3.0-Upgrade.md +70 -0
  7. data/4.0-Upgrade.md +53 -0
  8. data/COMM-LICENSE +56 -44
  9. data/Changes.md +644 -1
  10. data/Ent-Changes.md +173 -0
  11. data/Gemfile +27 -0
  12. data/LICENSE +1 -1
  13. data/Pro-2.0-Upgrade.md +138 -0
  14. data/Pro-3.0-Upgrade.md +44 -0
  15. data/Pro-Changes.md +457 -3
  16. data/README.md +46 -29
  17. data/Rakefile +6 -3
  18. data/bin/sidekiq +4 -0
  19. data/bin/sidekiqctl +41 -20
  20. data/bin/sidekiqload +154 -0
  21. data/code_of_conduct.md +50 -0
  22. data/lib/generators/sidekiq/templates/worker.rb.erb +9 -0
  23. data/lib/generators/sidekiq/templates/worker_spec.rb.erb +6 -0
  24. data/lib/generators/sidekiq/templates/worker_test.rb.erb +8 -0
  25. data/lib/generators/sidekiq/worker_generator.rb +49 -0
  26. data/lib/sidekiq.rb +141 -29
  27. data/lib/sidekiq/api.rb +540 -106
  28. data/lib/sidekiq/cli.rb +131 -71
  29. data/lib/sidekiq/client.rb +168 -96
  30. data/lib/sidekiq/core_ext.rb +36 -8
  31. data/lib/sidekiq/exception_handler.rb +20 -28
  32. data/lib/sidekiq/extensions/action_mailer.rb +25 -5
  33. data/lib/sidekiq/extensions/active_record.rb +8 -4
  34. data/lib/sidekiq/extensions/class_methods.rb +9 -5
  35. data/lib/sidekiq/extensions/generic_proxy.rb +1 -0
  36. data/lib/sidekiq/fetch.rb +45 -101
  37. data/lib/sidekiq/launcher.rb +144 -30
  38. data/lib/sidekiq/logging.rb +69 -12
  39. data/lib/sidekiq/manager.rb +90 -140
  40. data/lib/sidekiq/middleware/chain.rb +18 -5
  41. data/lib/sidekiq/middleware/i18n.rb +9 -2
  42. data/lib/sidekiq/middleware/server/active_record.rb +1 -1
  43. data/lib/sidekiq/middleware/server/logging.rb +11 -11
  44. data/lib/sidekiq/middleware/server/retry_jobs.rb +98 -44
  45. data/lib/sidekiq/paginator.rb +20 -8
  46. data/lib/sidekiq/processor.rb +157 -96
  47. data/lib/sidekiq/rails.rb +109 -5
  48. data/lib/sidekiq/redis_connection.rb +70 -24
  49. data/lib/sidekiq/scheduled.rb +122 -50
  50. data/lib/sidekiq/testing.rb +171 -31
  51. data/lib/sidekiq/testing/inline.rb +1 -0
  52. data/lib/sidekiq/util.rb +31 -5
  53. data/lib/sidekiq/version.rb +2 -1
  54. data/lib/sidekiq/web.rb +136 -263
  55. data/lib/sidekiq/web/action.rb +93 -0
  56. data/lib/sidekiq/web/application.rb +336 -0
  57. data/lib/sidekiq/web/helpers.rb +278 -0
  58. data/lib/sidekiq/web/router.rb +100 -0
  59. data/lib/sidekiq/worker.rb +40 -7
  60. data/sidekiq.gemspec +18 -14
  61. data/web/assets/images/favicon.ico +0 -0
  62. data/web/assets/images/{status-sd8051fd480.png → status.png} +0 -0
  63. data/web/assets/javascripts/application.js +67 -19
  64. data/web/assets/javascripts/dashboard.js +138 -29
  65. data/web/assets/stylesheets/application.css +267 -406
  66. data/web/assets/stylesheets/bootstrap.css +4 -8
  67. data/web/locales/cs.yml +78 -0
  68. data/web/locales/da.yml +9 -1
  69. data/web/locales/de.yml +18 -9
  70. data/web/locales/el.yml +68 -0
  71. data/web/locales/en.yml +19 -4
  72. data/web/locales/es.yml +10 -1
  73. data/web/locales/fa.yml +79 -0
  74. data/web/locales/fr.yml +50 -32
  75. data/web/locales/hi.yml +75 -0
  76. data/web/locales/it.yml +27 -18
  77. data/web/locales/ja.yml +27 -12
  78. data/web/locales/ko.yml +8 -3
  79. data/web/locales/{no.yml → nb.yml} +19 -5
  80. data/web/locales/nl.yml +8 -3
  81. data/web/locales/pl.yml +0 -1
  82. data/web/locales/pt-br.yml +11 -4
  83. data/web/locales/pt.yml +8 -1
  84. data/web/locales/ru.yml +39 -21
  85. data/web/locales/sv.yml +68 -0
  86. data/web/locales/ta.yml +75 -0
  87. data/web/locales/uk.yml +76 -0
  88. data/web/locales/zh-cn.yml +68 -0
  89. data/web/locales/zh-tw.yml +68 -0
  90. data/web/views/_footer.erb +17 -0
  91. data/web/views/_job_info.erb +72 -60
  92. data/web/views/_nav.erb +58 -25
  93. data/web/views/_paging.erb +5 -5
  94. data/web/views/_poll_link.erb +7 -0
  95. data/web/views/_summary.erb +20 -14
  96. data/web/views/busy.erb +94 -0
  97. data/web/views/dashboard.erb +34 -21
  98. data/web/views/dead.erb +34 -0
  99. data/web/views/layout.erb +8 -30
  100. data/web/views/morgue.erb +75 -0
  101. data/web/views/queue.erb +37 -30
  102. data/web/views/queues.erb +26 -20
  103. data/web/views/retries.erb +60 -47
  104. data/web/views/retry.erb +23 -19
  105. data/web/views/scheduled.erb +39 -35
  106. data/web/views/scheduled_job_info.erb +2 -1
  107. metadata +152 -195
  108. data/Contributing.md +0 -29
  109. data/config.ru +0 -18
  110. data/lib/sidekiq/actor.rb +0 -7
  111. data/lib/sidekiq/capistrano.rb +0 -54
  112. data/lib/sidekiq/yaml_patch.rb +0 -21
  113. data/test/config.yml +0 -11
  114. data/test/env_based_config.yml +0 -11
  115. data/test/fake_env.rb +0 -0
  116. data/test/helper.rb +0 -42
  117. data/test/test_api.rb +0 -341
  118. data/test/test_cli.rb +0 -326
  119. data/test/test_client.rb +0 -211
  120. data/test/test_exception_handler.rb +0 -124
  121. data/test/test_extensions.rb +0 -105
  122. data/test/test_fetch.rb +0 -44
  123. data/test/test_manager.rb +0 -83
  124. data/test/test_middleware.rb +0 -135
  125. data/test/test_processor.rb +0 -160
  126. data/test/test_redis_connection.rb +0 -97
  127. data/test/test_retry.rb +0 -306
  128. data/test/test_scheduled.rb +0 -86
  129. data/test/test_scheduling.rb +0 -47
  130. data/test/test_sidekiq.rb +0 -37
  131. data/test/test_testing.rb +0 -82
  132. data/test/test_testing_fake.rb +0 -265
  133. data/test/test_testing_inline.rb +0 -92
  134. data/test/test_util.rb +0 -18
  135. data/test/test_web.rb +0 -372
  136. data/web/assets/images/bootstrap/glyphicons-halflings-white.png +0 -0
  137. data/web/assets/images/bootstrap/glyphicons-halflings.png +0 -0
  138. data/web/assets/images/status/active.png +0 -0
  139. data/web/assets/images/status/idle.png +0 -0
  140. data/web/assets/javascripts/locales/README.md +0 -27
  141. data/web/assets/javascripts/locales/jquery.timeago.ar.js +0 -96
  142. data/web/assets/javascripts/locales/jquery.timeago.bg.js +0 -18
  143. data/web/assets/javascripts/locales/jquery.timeago.bs.js +0 -49
  144. data/web/assets/javascripts/locales/jquery.timeago.ca.js +0 -18
  145. data/web/assets/javascripts/locales/jquery.timeago.cy.js +0 -20
  146. data/web/assets/javascripts/locales/jquery.timeago.cz.js +0 -18
  147. data/web/assets/javascripts/locales/jquery.timeago.da.js +0 -18
  148. data/web/assets/javascripts/locales/jquery.timeago.de.js +0 -18
  149. data/web/assets/javascripts/locales/jquery.timeago.el.js +0 -18
  150. data/web/assets/javascripts/locales/jquery.timeago.en-short.js +0 -20
  151. data/web/assets/javascripts/locales/jquery.timeago.en.js +0 -20
  152. data/web/assets/javascripts/locales/jquery.timeago.es.js +0 -18
  153. data/web/assets/javascripts/locales/jquery.timeago.et.js +0 -18
  154. data/web/assets/javascripts/locales/jquery.timeago.fa.js +0 -22
  155. data/web/assets/javascripts/locales/jquery.timeago.fi.js +0 -28
  156. data/web/assets/javascripts/locales/jquery.timeago.fr-short.js +0 -16
  157. data/web/assets/javascripts/locales/jquery.timeago.fr.js +0 -17
  158. data/web/assets/javascripts/locales/jquery.timeago.he.js +0 -18
  159. data/web/assets/javascripts/locales/jquery.timeago.hr.js +0 -49
  160. data/web/assets/javascripts/locales/jquery.timeago.hu.js +0 -18
  161. data/web/assets/javascripts/locales/jquery.timeago.hy.js +0 -18
  162. data/web/assets/javascripts/locales/jquery.timeago.id.js +0 -18
  163. data/web/assets/javascripts/locales/jquery.timeago.it.js +0 -16
  164. data/web/assets/javascripts/locales/jquery.timeago.ja.js +0 -19
  165. data/web/assets/javascripts/locales/jquery.timeago.ko.js +0 -17
  166. data/web/assets/javascripts/locales/jquery.timeago.lt.js +0 -20
  167. data/web/assets/javascripts/locales/jquery.timeago.mk.js +0 -20
  168. data/web/assets/javascripts/locales/jquery.timeago.nl.js +0 -20
  169. data/web/assets/javascripts/locales/jquery.timeago.no.js +0 -18
  170. data/web/assets/javascripts/locales/jquery.timeago.pl.js +0 -31
  171. data/web/assets/javascripts/locales/jquery.timeago.pt-br.js +0 -16
  172. data/web/assets/javascripts/locales/jquery.timeago.pt.js +0 -16
  173. data/web/assets/javascripts/locales/jquery.timeago.ro.js +0 -18
  174. data/web/assets/javascripts/locales/jquery.timeago.rs.js +0 -49
  175. data/web/assets/javascripts/locales/jquery.timeago.ru.js +0 -34
  176. data/web/assets/javascripts/locales/jquery.timeago.sk.js +0 -18
  177. data/web/assets/javascripts/locales/jquery.timeago.sl.js +0 -44
  178. data/web/assets/javascripts/locales/jquery.timeago.sv.js +0 -18
  179. data/web/assets/javascripts/locales/jquery.timeago.th.js +0 -20
  180. data/web/assets/javascripts/locales/jquery.timeago.tr.js +0 -16
  181. data/web/assets/javascripts/locales/jquery.timeago.uk.js +0 -34
  182. data/web/assets/javascripts/locales/jquery.timeago.uz.js +0 -19
  183. data/web/assets/javascripts/locales/jquery.timeago.zh-CN.js +0 -20
  184. data/web/assets/javascripts/locales/jquery.timeago.zh-TW.js +0 -20
  185. data/web/views/_poll.erb +0 -14
  186. data/web/views/_workers.erb +0 -29
  187. data/web/views/index.erb +0 -16
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  begin
2
3
  require 'active_support/core_ext/class/attribute'
3
4
  rescue LoadError
@@ -6,7 +7,6 @@ rescue LoadError
6
7
  # Class#class_attribute helper.
7
8
  class Class
8
9
  def class_attribute(*attrs)
9
- instance_reader = true
10
10
  instance_writer = true
11
11
 
12
12
  attrs.each do |name|
@@ -29,14 +29,12 @@ rescue LoadError
29
29
  val
30
30
  end
31
31
 
32
- if instance_reader
33
- def #{name}
34
- defined?(@#{name}) ? @#{name} : self.class.#{name}
35
- end
32
+ def #{name}
33
+ defined?(@#{name}) ? @#{name} : self.class.#{name}
34
+ end
36
35
 
37
- def #{name}?
38
- !!#{name}
39
- end
36
+ def #{name}?
37
+ !!#{name}
40
38
  end
41
39
  RUBY
42
40
 
@@ -53,6 +51,7 @@ end
53
51
 
54
52
  begin
55
53
  require 'active_support/core_ext/hash/keys'
54
+ require 'active_support/core_ext/hash/deep_merge'
56
55
  rescue LoadError
57
56
  class Hash
58
57
  def stringify_keys
@@ -68,6 +67,22 @@ rescue LoadError
68
67
  end
69
68
  self
70
69
  end if !{}.respond_to?(:symbolize_keys)
70
+
71
+ def deep_merge(other_hash, &block)
72
+ dup.deep_merge!(other_hash, &block)
73
+ end if !{}.respond_to?(:deep_merge)
74
+
75
+ def deep_merge!(other_hash, &block)
76
+ other_hash.each_pair do |k,v|
77
+ tv = self[k]
78
+ if tv.is_a?(Hash) && v.is_a?(Hash)
79
+ self[k] = tv.deep_merge(v, &block)
80
+ else
81
+ self[k] = block && tv ? block.call(k, tv, v) : v
82
+ end
83
+ end
84
+ self
85
+ end if !{}.respond_to?(:deep_merge!)
71
86
  end
72
87
  end
73
88
 
@@ -89,3 +104,16 @@ rescue LoadError
89
104
  end
90
105
 
91
106
 
107
+ begin
108
+ require 'active_support/core_ext/kernel/reporting'
109
+ rescue LoadError
110
+ module Kernel
111
+ module_function
112
+ def silence_warnings
113
+ old_verbose, $VERBOSE = $VERBOSE, nil
114
+ yield
115
+ ensure
116
+ $VERBOSE = old_verbose
117
+ end
118
+ end
119
+ end
@@ -1,39 +1,31 @@
1
+ # frozen_string_literal: true
2
+ require 'sidekiq'
3
+
1
4
  module Sidekiq
2
5
  module ExceptionHandler
3
6
 
4
- def handle_exception(ex, ctxHash={})
5
- Sidekiq.logger.warn(ctxHash) if !ctxHash.empty?
6
- Sidekiq.logger.warn ex
7
- Sidekiq.logger.warn ex.backtrace.join("\n")
8
- # This list of services is getting a bit ridiculous.
9
- # For future error services, please add your own
10
- # middleware like BugSnag does:
11
- # https://github.com/bugsnag/bugsnag-ruby/blob/master/lib/bugsnag/sidekiq.rb
12
- send_to_airbrake(ctxHash, ex) if defined?(::Airbrake)
13
- send_to_honeybadger(ctxHash, ex) if defined?(::Honeybadger)
14
- send_to_exceptional(ctxHash, ex) if defined?(::Exceptional)
15
- send_to_exception_notifier(ctxHash, ex) if defined?(::ExceptionNotifier)
16
- end
17
-
18
- private
19
-
20
- def send_to_airbrake(hash, ex)
21
- ::Airbrake.notify_or_ignore(ex, :parameters => hash)
22
- end
7
+ class Logger
8
+ def call(ex, ctxHash)
9
+ Sidekiq.logger.warn(Sidekiq.dump_json(ctxHash)) if !ctxHash.empty?
10
+ Sidekiq.logger.warn "#{ex.class.name}: #{ex.message}"
11
+ Sidekiq.logger.warn ex.backtrace.join("\n") unless ex.backtrace.nil?
12
+ end
23
13
 
24
- def send_to_honeybadger(hash, ex)
25
- ::Honeybadger.notify_or_ignore(ex, :parameters => hash)
14
+ # Set up default handler which just logs the error
15
+ Sidekiq.error_handlers << Sidekiq::ExceptionHandler::Logger.new
26
16
  end
27
17
 
28
- def send_to_exceptional(hash, ex)
29
- if ::Exceptional::Config.should_send_to_api?
30
- ::Exceptional.context(hash)
31
- ::Exceptional::Remote.error(::Exceptional::ExceptionData.new(ex))
18
+ def handle_exception(ex, ctxHash={})
19
+ Sidekiq.error_handlers.each do |handler|
20
+ begin
21
+ handler.call(ex, ctxHash)
22
+ rescue => ex
23
+ Sidekiq.logger.error "!!! ERROR HANDLER THREW AN ERROR !!!"
24
+ Sidekiq.logger.error ex
25
+ Sidekiq.logger.error ex.backtrace.join("\n") unless ex.backtrace.nil?
26
+ end
32
27
  end
33
28
  end
34
29
 
35
- def send_to_exception_notifier(hash, ex)
36
- ::ExceptionNotifier.notify_exception(ex, :data => {:message => hash})
37
- end
38
30
  end
39
31
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'sidekiq/extensions/generic_proxy'
2
3
 
3
4
  module Sidekiq
@@ -14,23 +15,42 @@ module Sidekiq
14
15
 
15
16
  def perform(yml)
16
17
  (target, method_name, args) = YAML.load(yml)
17
- msg = target.send(method_name, *args)
18
+ msg = target.public_send(method_name, *args)
18
19
  # The email method can return nil, which causes ActionMailer to return
19
20
  # an undeliverable empty message.
20
- msg.deliver if msg && (msg.to || msg.cc || msg.bcc) && msg.from
21
+ if msg
22
+ deliver(msg)
23
+ else
24
+ raise "#{target.name}##{method_name} returned an undeliverable mail object"
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ def deliver(msg)
31
+ if msg.respond_to?(:deliver_now)
32
+ # Rails 4.2/5.0
33
+ msg.deliver_now
34
+ else
35
+ # Rails 3.2/4.0/4.1
36
+ msg.deliver
37
+ end
21
38
  end
22
39
  end
23
40
 
24
41
  module ActionMailer
25
- def delay(options={})
42
+ def sidekiq_delay(options={})
26
43
  Proxy.new(DelayedMailer, self, options)
27
44
  end
28
- def delay_for(interval, options={})
45
+ def sidekiq_delay_for(interval, options={})
29
46
  Proxy.new(DelayedMailer, self, options.merge('at' => Time.now.to_f + interval.to_f))
30
47
  end
31
- def delay_until(timestamp, options={})
48
+ def sidekiq_delay_until(timestamp, options={})
32
49
  Proxy.new(DelayedMailer, self, options.merge('at' => timestamp.to_f))
33
50
  end
51
+ alias_method :delay, :sidekiq_delay
52
+ alias_method :delay_for, :sidekiq_delay_for
53
+ alias_method :delay_until, :sidekiq_delay_until
34
54
  end
35
55
 
36
56
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'sidekiq/extensions/generic_proxy'
2
3
 
3
4
  module Sidekiq
@@ -16,20 +17,23 @@ module Sidekiq
16
17
 
17
18
  def perform(yml)
18
19
  (target, method_name, args) = YAML.load(yml)
19
- target.send(method_name, *args)
20
+ target.__send__(method_name, *args)
20
21
  end
21
22
  end
22
23
 
23
24
  module ActiveRecord
24
- def delay(options={})
25
+ def sidekiq_delay(options={})
25
26
  Proxy.new(DelayedModel, self, options)
26
27
  end
27
- def delay_for(interval, options={})
28
+ def sidekiq_delay_for(interval, options={})
28
29
  Proxy.new(DelayedModel, self, options.merge('at' => Time.now.to_f + interval.to_f))
29
30
  end
30
- def delay_until(timestamp, options={})
31
+ def sidekiq_delay_until(timestamp, options={})
31
32
  Proxy.new(DelayedModel, self, options.merge('at' => timestamp.to_f))
32
33
  end
34
+ alias_method :delay, :sidekiq_delay
35
+ alias_method :delay_for, :sidekiq_delay_for
36
+ alias_method :delay_until, :sidekiq_delay_until
33
37
  end
34
38
 
35
39
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'sidekiq/extensions/generic_proxy'
2
3
 
3
4
  module Sidekiq
@@ -14,23 +15,26 @@ module Sidekiq
14
15
 
15
16
  def perform(yml)
16
17
  (target, method_name, args) = YAML.load(yml)
17
- target.send(method_name, *args)
18
+ target.__send__(method_name, *args)
18
19
  end
19
20
  end
20
21
 
21
22
  module Klass
22
- def delay(options={})
23
+ def sidekiq_delay(options={})
23
24
  Proxy.new(DelayedClass, self, options)
24
25
  end
25
- def delay_for(interval, options={})
26
+ def sidekiq_delay_for(interval, options={})
26
27
  Proxy.new(DelayedClass, self, options.merge('at' => Time.now.to_f + interval.to_f))
27
28
  end
28
- def delay_until(timestamp, options={})
29
+ def sidekiq_delay_until(timestamp, options={})
29
30
  Proxy.new(DelayedClass, self, options.merge('at' => timestamp.to_f))
30
31
  end
32
+ alias_method :delay, :sidekiq_delay
33
+ alias_method :delay_for, :sidekiq_delay_for
34
+ alias_method :delay_until, :sidekiq_delay_until
31
35
  end
32
36
 
33
37
  end
34
38
  end
35
39
 
36
- Module.send(:include, Sidekiq::Extensions::Klass)
40
+ Module.__send__(:include, Sidekiq::Extensions::Klass) unless defined?(::Rails)
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'yaml'
2
3
 
3
4
  module Sidekiq
@@ -1,88 +1,35 @@
1
+ # frozen_string_literal: true
1
2
  require 'sidekiq'
2
- require 'sidekiq/actor'
3
3
 
4
4
  module Sidekiq
5
- ##
6
- # The Fetcher blocks on Redis, waiting for a message to process
7
- # from the queues. It gets the message and hands it to the Manager
8
- # to assign to a ready Processor.
9
- class Fetcher
10
- include Util
11
- include Actor
12
-
13
- TIMEOUT = 1
14
-
15
- def initialize(mgr, options)
16
- @down = nil
17
- @mgr = mgr
18
- @strategy = Fetcher.strategy.new(options)
19
- end
20
-
21
- # Fetching is straightforward: the Manager makes a fetch
22
- # request for each idle processor when Sidekiq starts and
23
- # then issues a new fetch request every time a Processor
24
- # finishes a message.
25
- #
26
- # Because we have to shut down cleanly, we can't block
27
- # forever and we can't loop forever. Instead we reschedule
28
- # a new fetch if the current fetch turned up nothing.
29
- def fetch
30
- watchdog('Fetcher#fetch died') do
31
- return if Sidekiq::Fetcher.done?
32
-
33
- begin
34
- work = @strategy.retrieve_work
35
- ::Sidekiq.logger.info("Redis is online, #{Time.now.to_f - @down.to_f} sec downtime") if @down
36
- @down = nil
5
+ class BasicFetch
6
+ # We want the fetch operation to timeout every few seconds so the thread
7
+ # can check if the process is shutting down.
8
+ TIMEOUT = 2
37
9
 
38
- if work
39
- @mgr.async.assign(work)
40
- else
41
- after(0) { fetch }
42
- end
43
- rescue => ex
44
- handle_exception(ex)
45
- end
10
+ UnitOfWork = Struct.new(:queue, :job) do
11
+ def acknowledge
12
+ # nothing to do
13
+ end
46
14
 
15
+ def queue_name
16
+ queue.sub(/.*queue:/, ''.freeze)
47
17
  end
48
- end
49
18
 
50
- def handle_exception(ex)
51
- if !@down
52
- logger.error("Error fetching message: #{ex}")
53
- ex.backtrace.each do |bt|
54
- logger.error(bt)
19
+ def requeue
20
+ Sidekiq.redis do |conn|
21
+ conn.rpush("queue:#{queue_name}", job)
55
22
  end
56
23
  end
57
- @down ||= Time.now
58
- sleep(TIMEOUT)
59
- after(0) { fetch }
60
- rescue Task::TerminatedError
61
- # If redis is down when we try to shut down, all the fetch backlog
62
- # raises these errors. Haven't been able to figure out what I'm doing wrong.
63
- end
64
-
65
- # Ugh. Say hello to a bloody hack.
66
- # Can't find a clean way to get the fetcher to just stop processing
67
- # its mailbox when shutdown starts.
68
- def self.done!
69
- @done = true
70
- end
71
-
72
- def self.done?
73
- @done
74
24
  end
75
25
 
76
- def self.strategy
77
- Sidekiq.options[:fetch] || BasicFetch
78
- end
79
- end
80
-
81
- class BasicFetch
82
26
  def initialize(options)
83
27
  @strictly_ordered_queues = !!options[:strict]
84
28
  @queues = options[:queues].map { |q| "queue:#{q}" }
85
- @unique_queues = @queues.uniq
29
+ if @strictly_ordered_queues
30
+ @queues = @queues.uniq
31
+ @queues << TIMEOUT
32
+ end
86
33
  end
87
34
 
88
35
  def retrieve_work
@@ -90,48 +37,45 @@ module Sidekiq
90
37
  UnitOfWork.new(*work) if work
91
38
  end
92
39
 
93
- def self.bulk_requeue(inprogress)
40
+ # Creating the Redis#brpop command takes into account any
41
+ # configured queue weights. By default Redis#brpop returns
42
+ # data from the first queue that has pending elements. We
43
+ # recreate the queue command each time we invoke Redis#brpop
44
+ # to honor weights and avoid queue starvation.
45
+ def queues_cmd
46
+ if @strictly_ordered_queues
47
+ @queues
48
+ else
49
+ queues = @queues.shuffle.uniq
50
+ queues << TIMEOUT
51
+ queues
52
+ end
53
+ end
54
+
55
+
56
+ # By leaving this as a class method, it can be pluggable and used by the Manager actor. Making it
57
+ # an instance method will make it async to the Fetcher actor
58
+ def self.bulk_requeue(inprogress, options)
59
+ return if inprogress.empty?
60
+
94
61
  Sidekiq.logger.debug { "Re-queueing terminated jobs" }
95
62
  jobs_to_requeue = {}
96
63
  inprogress.each do |unit_of_work|
97
64
  jobs_to_requeue[unit_of_work.queue_name] ||= []
98
- jobs_to_requeue[unit_of_work.queue_name] << unit_of_work.message
65
+ jobs_to_requeue[unit_of_work.queue_name] << unit_of_work.job
99
66
  end
100
67
 
101
68
  Sidekiq.redis do |conn|
102
- jobs_to_requeue.each do |queue, jobs|
103
- conn.rpush("queue:#{queue}", jobs)
69
+ conn.pipelined do
70
+ jobs_to_requeue.each do |queue, jobs|
71
+ conn.rpush("queue:#{queue}", jobs)
72
+ end
104
73
  end
105
74
  end
106
- Sidekiq.logger.info("Pushed #{inprogress.size} messages back to Redis")
75
+ Sidekiq.logger.info("Pushed #{inprogress.size} jobs back to Redis")
107
76
  rescue => ex
108
77
  Sidekiq.logger.warn("Failed to requeue #{inprogress.size} jobs: #{ex.message}")
109
78
  end
110
79
 
111
- UnitOfWork = Struct.new(:queue, :message) do
112
- def acknowledge
113
- # nothing to do
114
- end
115
-
116
- def queue_name
117
- queue.gsub(/.*queue:/, '')
118
- end
119
-
120
- def requeue
121
- Sidekiq.redis do |conn|
122
- conn.rpush("queue:#{queue_name}", message)
123
- end
124
- end
125
- end
126
-
127
- # Creating the Redis#blpop command takes into account any
128
- # configured queue weights. By default Redis#blpop returns
129
- # data from the first queue that has pending elements. We
130
- # recreate the queue command each time we invoke Redis#blpop
131
- # to honor weights and avoid queue starvation.
132
- def queues_cmd
133
- queues = @strictly_ordered_queues ? @unique_queues.dup : @queues.shuffle.uniq
134
- queues << Sidekiq::Fetcher::TIMEOUT
135
- end
136
80
  end
137
81
  end