sidekiq 4.2.10 → 7.3.10

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.
Files changed (159) hide show
  1. checksums.yaml +5 -5
  2. data/Changes.md +932 -7
  3. data/LICENSE.txt +9 -0
  4. data/README.md +49 -50
  5. data/bin/multi_queue_bench +271 -0
  6. data/bin/sidekiq +22 -3
  7. data/bin/sidekiqload +218 -116
  8. data/bin/sidekiqmon +11 -0
  9. data/lib/active_job/queue_adapters/sidekiq_adapter.rb +75 -0
  10. data/lib/generators/sidekiq/job_generator.rb +59 -0
  11. data/lib/generators/sidekiq/templates/{worker.rb.erb → job.rb.erb} +2 -2
  12. data/lib/generators/sidekiq/templates/job_spec.rb.erb +6 -0
  13. data/lib/generators/sidekiq/templates/{worker_test.rb.erb → job_test.rb.erb} +1 -1
  14. data/lib/sidekiq/api.rb +710 -322
  15. data/lib/sidekiq/capsule.rb +132 -0
  16. data/lib/sidekiq/cli.rb +268 -248
  17. data/lib/sidekiq/client.rb +153 -101
  18. data/lib/sidekiq/component.rb +90 -0
  19. data/lib/sidekiq/config.rb +311 -0
  20. data/lib/sidekiq/deploy.rb +64 -0
  21. data/lib/sidekiq/embedded.rb +63 -0
  22. data/lib/sidekiq/fetch.rb +50 -42
  23. data/lib/sidekiq/iterable_job.rb +55 -0
  24. data/lib/sidekiq/job/interrupt_handler.rb +24 -0
  25. data/lib/sidekiq/job/iterable/active_record_enumerator.rb +53 -0
  26. data/lib/sidekiq/job/iterable/csv_enumerator.rb +47 -0
  27. data/lib/sidekiq/job/iterable/enumerators.rb +135 -0
  28. data/lib/sidekiq/job/iterable.rb +294 -0
  29. data/lib/sidekiq/job.rb +385 -0
  30. data/lib/sidekiq/job_logger.rb +52 -0
  31. data/lib/sidekiq/job_retry.rb +305 -0
  32. data/lib/sidekiq/job_util.rb +109 -0
  33. data/lib/sidekiq/launcher.rb +208 -108
  34. data/lib/sidekiq/logger.rb +131 -0
  35. data/lib/sidekiq/manager.rb +43 -47
  36. data/lib/sidekiq/metrics/query.rb +158 -0
  37. data/lib/sidekiq/metrics/shared.rb +106 -0
  38. data/lib/sidekiq/metrics/tracking.rb +148 -0
  39. data/lib/sidekiq/middleware/chain.rb +113 -56
  40. data/lib/sidekiq/middleware/current_attributes.rb +128 -0
  41. data/lib/sidekiq/middleware/i18n.rb +9 -7
  42. data/lib/sidekiq/middleware/modules.rb +23 -0
  43. data/lib/sidekiq/monitor.rb +147 -0
  44. data/lib/sidekiq/paginator.rb +33 -15
  45. data/lib/sidekiq/processor.rb +188 -98
  46. data/lib/sidekiq/rails.rb +53 -92
  47. data/lib/sidekiq/redis_client_adapter.rb +114 -0
  48. data/lib/sidekiq/redis_connection.rb +86 -77
  49. data/lib/sidekiq/ring_buffer.rb +32 -0
  50. data/lib/sidekiq/scheduled.rb +140 -51
  51. data/lib/sidekiq/sd_notify.rb +149 -0
  52. data/lib/sidekiq/systemd.rb +26 -0
  53. data/lib/sidekiq/testing/inline.rb +6 -5
  54. data/lib/sidekiq/testing.rb +95 -85
  55. data/lib/sidekiq/transaction_aware_client.rb +59 -0
  56. data/lib/sidekiq/version.rb +7 -1
  57. data/lib/sidekiq/web/action.rb +40 -18
  58. data/lib/sidekiq/web/application.rb +189 -89
  59. data/lib/sidekiq/web/csrf_protection.rb +183 -0
  60. data/lib/sidekiq/web/helpers.rb +239 -101
  61. data/lib/sidekiq/web/router.rb +28 -21
  62. data/lib/sidekiq/web.rb +123 -110
  63. data/lib/sidekiq/worker_compatibility_alias.rb +13 -0
  64. data/lib/sidekiq.rb +97 -185
  65. data/sidekiq.gemspec +26 -27
  66. data/web/assets/images/apple-touch-icon.png +0 -0
  67. data/web/assets/javascripts/application.js +157 -61
  68. data/web/assets/javascripts/base-charts.js +106 -0
  69. data/web/assets/javascripts/chart.min.js +13 -0
  70. data/web/assets/javascripts/chartjs-plugin-annotation.min.js +7 -0
  71. data/web/assets/javascripts/dashboard-charts.js +194 -0
  72. data/web/assets/javascripts/dashboard.js +43 -280
  73. data/web/assets/javascripts/metrics.js +298 -0
  74. data/web/assets/stylesheets/application-dark.css +147 -0
  75. data/web/assets/stylesheets/application-rtl.css +163 -0
  76. data/web/assets/stylesheets/application.css +176 -196
  77. data/web/assets/stylesheets/bootstrap-rtl.min.css +9 -0
  78. data/web/assets/stylesheets/bootstrap.css +2 -2
  79. data/web/locales/ar.yml +87 -0
  80. data/web/locales/cs.yml +62 -62
  81. data/web/locales/da.yml +60 -53
  82. data/web/locales/de.yml +65 -53
  83. data/web/locales/el.yml +43 -24
  84. data/web/locales/en.yml +88 -64
  85. data/web/locales/es.yml +70 -53
  86. data/web/locales/fa.yml +65 -64
  87. data/web/locales/fr.yml +82 -62
  88. data/web/locales/gd.yml +98 -0
  89. data/web/locales/he.yml +80 -0
  90. data/web/locales/hi.yml +59 -59
  91. data/web/locales/it.yml +85 -54
  92. data/web/locales/ja.yml +74 -62
  93. data/web/locales/ko.yml +52 -52
  94. data/web/locales/lt.yml +83 -0
  95. data/web/locales/nb.yml +61 -61
  96. data/web/locales/nl.yml +52 -52
  97. data/web/locales/pl.yml +45 -45
  98. data/web/locales/pt-br.yml +82 -55
  99. data/web/locales/pt.yml +51 -51
  100. data/web/locales/ru.yml +68 -63
  101. data/web/locales/sv.yml +53 -53
  102. data/web/locales/ta.yml +60 -60
  103. data/web/locales/tr.yml +100 -0
  104. data/web/locales/uk.yml +85 -61
  105. data/web/locales/ur.yml +80 -0
  106. data/web/locales/vi.yml +83 -0
  107. data/web/locales/zh-cn.yml +42 -16
  108. data/web/locales/zh-tw.yml +41 -8
  109. data/web/views/_footer.erb +20 -3
  110. data/web/views/_job_info.erb +21 -4
  111. data/web/views/_metrics_period_select.erb +12 -0
  112. data/web/views/_nav.erb +5 -19
  113. data/web/views/_paging.erb +3 -1
  114. data/web/views/_poll_link.erb +3 -6
  115. data/web/views/_summary.erb +7 -7
  116. data/web/views/busy.erb +85 -31
  117. data/web/views/dashboard.erb +53 -20
  118. data/web/views/dead.erb +3 -3
  119. data/web/views/filtering.erb +6 -0
  120. data/web/views/layout.erb +17 -6
  121. data/web/views/metrics.erb +90 -0
  122. data/web/views/metrics_for_job.erb +59 -0
  123. data/web/views/morgue.erb +15 -16
  124. data/web/views/queue.erb +35 -25
  125. data/web/views/queues.erb +20 -4
  126. data/web/views/retries.erb +19 -16
  127. data/web/views/retry.erb +3 -3
  128. data/web/views/scheduled.erb +19 -17
  129. metadata +103 -194
  130. data/.github/contributing.md +0 -32
  131. data/.github/issue_template.md +0 -9
  132. data/.gitignore +0 -12
  133. data/.travis.yml +0 -18
  134. data/3.0-Upgrade.md +0 -70
  135. data/4.0-Upgrade.md +0 -53
  136. data/COMM-LICENSE +0 -95
  137. data/Ent-Changes.md +0 -173
  138. data/Gemfile +0 -29
  139. data/LICENSE +0 -9
  140. data/Pro-2.0-Upgrade.md +0 -138
  141. data/Pro-3.0-Upgrade.md +0 -44
  142. data/Pro-Changes.md +0 -628
  143. data/Rakefile +0 -12
  144. data/bin/sidekiqctl +0 -99
  145. data/code_of_conduct.md +0 -50
  146. data/lib/generators/sidekiq/templates/worker_spec.rb.erb +0 -6
  147. data/lib/generators/sidekiq/worker_generator.rb +0 -49
  148. data/lib/sidekiq/core_ext.rb +0 -119
  149. data/lib/sidekiq/exception_handler.rb +0 -31
  150. data/lib/sidekiq/extensions/action_mailer.rb +0 -57
  151. data/lib/sidekiq/extensions/active_record.rb +0 -40
  152. data/lib/sidekiq/extensions/class_methods.rb +0 -40
  153. data/lib/sidekiq/extensions/generic_proxy.rb +0 -25
  154. data/lib/sidekiq/logging.rb +0 -106
  155. data/lib/sidekiq/middleware/server/active_record.rb +0 -13
  156. data/lib/sidekiq/middleware/server/logging.rb +0 -31
  157. data/lib/sidekiq/middleware/server/retry_jobs.rb +0 -205
  158. data/lib/sidekiq/util.rb +0 -63
  159. data/lib/sidekiq/worker.rb +0 -121
@@ -1,205 +0,0 @@
1
- require 'sidekiq/scheduled'
2
- require 'sidekiq/api'
3
-
4
- module Sidekiq
5
- module Middleware
6
- module Server
7
- ##
8
- # Automatically retry jobs that fail in Sidekiq.
9
- # Sidekiq's retry support assumes a typical development lifecycle:
10
- #
11
- # 0. Push some code changes with a bug in it.
12
- # 1. Bug causes job processing to fail, Sidekiq's middleware captures
13
- # the job and pushes it onto a retry queue.
14
- # 2. Sidekiq retries jobs in the retry queue multiple times with
15
- # an exponential delay, the job continues to fail.
16
- # 3. After a few days, a developer deploys a fix. The job is
17
- # reprocessed successfully.
18
- # 4. Once retries are exhausted, Sidekiq will give up and move the
19
- # job to the Dead Job Queue (aka morgue) where it must be dealt with
20
- # manually in the Web UI.
21
- # 5. After 6 months on the DJQ, Sidekiq will discard the job.
22
- #
23
- # A job looks like:
24
- #
25
- # { 'class' => 'HardWorker', 'args' => [1, 2, 'foo'], 'retry' => true }
26
- #
27
- # The 'retry' option also accepts a number (in place of 'true'):
28
- #
29
- # { 'class' => 'HardWorker', 'args' => [1, 2, 'foo'], 'retry' => 5 }
30
- #
31
- # The job will be retried this number of times before giving up. (If simply
32
- # 'true', Sidekiq retries 25 times)
33
- #
34
- # We'll add a bit more data to the job to support retries:
35
- #
36
- # * 'queue' - the queue to use
37
- # * 'retry_count' - number of times we've retried so far.
38
- # * 'error_message' - the message from the exception
39
- # * 'error_class' - the exception class
40
- # * 'failed_at' - the first time it failed
41
- # * 'retried_at' - the last time it was retried
42
- # * 'backtrace' - the number of lines of error backtrace to store
43
- #
44
- # We don't store the backtrace by default as that can add a lot of overhead
45
- # to the job and everyone is using an error service, right?
46
- #
47
- # The default number of retry attempts is 25 which works out to about 3 weeks
48
- # of retries. You can pass a value for the max number of retry attempts when
49
- # adding the middleware using the options hash:
50
- #
51
- # Sidekiq.configure_server do |config|
52
- # config.server_middleware do |chain|
53
- # chain.add Sidekiq::Middleware::Server::RetryJobs, :max_retries => 7
54
- # end
55
- # end
56
- #
57
- # or limit the number of retries for a particular worker with:
58
- #
59
- # class MyWorker
60
- # include Sidekiq::Worker
61
- # sidekiq_options :retry => 10
62
- # end
63
- #
64
- class RetryJobs
65
- include Sidekiq::Util
66
-
67
- DEFAULT_MAX_RETRY_ATTEMPTS = 25
68
-
69
- def initialize(options = {})
70
- @max_retries = options.fetch(:max_retries, DEFAULT_MAX_RETRY_ATTEMPTS)
71
- end
72
-
73
- def call(worker, msg, queue)
74
- yield
75
- rescue Sidekiq::Shutdown
76
- # ignore, will be pushed back onto queue during hard_shutdown
77
- raise
78
- rescue Exception => e
79
- # ignore, will be pushed back onto queue during hard_shutdown
80
- raise Sidekiq::Shutdown if exception_caused_by_shutdown?(e)
81
-
82
- raise e unless msg['retry']
83
- attempt_retry(worker, msg, queue, e)
84
- end
85
-
86
- private
87
-
88
- def attempt_retry(worker, msg, queue, exception)
89
- max_retry_attempts = retry_attempts_from(msg['retry'], @max_retries)
90
-
91
- msg['queue'] = if msg['retry_queue']
92
- msg['retry_queue']
93
- else
94
- queue
95
- end
96
-
97
- # App code can stuff all sorts of crazy binary data into the error message
98
- # that won't convert to JSON.
99
- m = exception.message.to_s[0, 10_000]
100
- if m.respond_to?(:scrub!)
101
- m.force_encoding("utf-8")
102
- m.scrub!
103
- end
104
-
105
- msg['error_message'] = m
106
- msg['error_class'] = exception.class.name
107
- count = if msg['retry_count']
108
- msg['retried_at'] = Time.now.to_f
109
- msg['retry_count'] += 1
110
- else
111
- msg['failed_at'] = Time.now.to_f
112
- msg['retry_count'] = 0
113
- end
114
-
115
- if msg['backtrace'] == true
116
- msg['error_backtrace'] = exception.backtrace
117
- elsif !msg['backtrace']
118
- # do nothing
119
- elsif msg['backtrace'].to_i != 0
120
- msg['error_backtrace'] = exception.backtrace[0...msg['backtrace'].to_i]
121
- end
122
-
123
- if count < max_retry_attempts
124
- delay = delay_for(worker, count, exception)
125
- logger.debug { "Failure! Retry #{count} in #{delay} seconds" }
126
- retry_at = Time.now.to_f + delay
127
- payload = Sidekiq.dump_json(msg)
128
- Sidekiq.redis do |conn|
129
- conn.zadd('retry', retry_at.to_s, payload)
130
- end
131
- else
132
- # Goodbye dear message, you (re)tried your best I'm sure.
133
- retries_exhausted(worker, msg, exception)
134
- end
135
-
136
- raise exception
137
- end
138
-
139
- def retries_exhausted(worker, msg, exception)
140
- logger.debug { "Retries exhausted for job" }
141
- begin
142
- block = worker.sidekiq_retries_exhausted_block || Sidekiq.default_retries_exhausted
143
- block.call(msg, exception) if block
144
- rescue => e
145
- handle_exception(e, { context: "Error calling retries_exhausted for #{worker.class}", job: msg })
146
- end
147
-
148
- send_to_morgue(msg) unless msg['dead'] == false
149
- end
150
-
151
- def send_to_morgue(msg)
152
- Sidekiq.logger.info { "Adding dead #{msg['class']} job #{msg['jid']}" }
153
- payload = Sidekiq.dump_json(msg)
154
- now = Time.now.to_f
155
- Sidekiq.redis do |conn|
156
- conn.multi do
157
- conn.zadd('dead', now, payload)
158
- conn.zremrangebyscore('dead', '-inf', now - DeadSet.timeout)
159
- conn.zremrangebyrank('dead', 0, -DeadSet.max_jobs)
160
- end
161
- end
162
- end
163
-
164
- def retry_attempts_from(msg_retry, default)
165
- if msg_retry.is_a?(Integer)
166
- msg_retry
167
- else
168
- default
169
- end
170
- end
171
-
172
- def delay_for(worker, count, exception)
173
- worker.sidekiq_retry_in_block? && retry_in(worker, count, exception) || seconds_to_delay(count)
174
- end
175
-
176
- # delayed_job uses the same basic formula
177
- def seconds_to_delay(count)
178
- (count ** 4) + 15 + (rand(30)*(count+1))
179
- end
180
-
181
- def retry_in(worker, count, exception)
182
- begin
183
- worker.sidekiq_retry_in_block.call(count, exception).to_i
184
- rescue Exception => e
185
- handle_exception(e, { context: "Failure scheduling retry using the defined `sidekiq_retry_in` in #{worker.class.name}, falling back to default" })
186
- nil
187
- end
188
- end
189
-
190
- def exception_caused_by_shutdown?(e, checked_causes = [])
191
- # In Ruby 2.1.0 only, check if exception is a result of shutdown.
192
- return false unless defined?(e.cause)
193
-
194
- # Handle circular causes
195
- checked_causes << e.object_id
196
- return false if checked_causes.include?(e.cause.object_id)
197
-
198
- e.cause.instance_of?(Sidekiq::Shutdown) ||
199
- exception_caused_by_shutdown?(e.cause, checked_causes)
200
- end
201
-
202
- end
203
- end
204
- end
205
- end
data/lib/sidekiq/util.rb DELETED
@@ -1,63 +0,0 @@
1
- # frozen_string_literal: true
2
- require 'socket'
3
- require 'securerandom'
4
- require 'sidekiq/exception_handler'
5
- require 'sidekiq/core_ext'
6
-
7
- module Sidekiq
8
- ##
9
- # This module is part of Sidekiq core and not intended for extensions.
10
- #
11
- module Util
12
- include ExceptionHandler
13
-
14
- EXPIRY = 60 * 60 * 24
15
-
16
- def watchdog(last_words)
17
- yield
18
- rescue Exception => ex
19
- handle_exception(ex, { context: last_words })
20
- raise ex
21
- end
22
-
23
- def safe_thread(name, &block)
24
- Thread.new do
25
- Thread.current['sidekiq_label'] = name
26
- watchdog(name, &block)
27
- end
28
- end
29
-
30
- def logger
31
- Sidekiq.logger
32
- end
33
-
34
- def redis(&block)
35
- Sidekiq.redis(&block)
36
- end
37
-
38
- def hostname
39
- ENV['DYNO'] || Socket.gethostname
40
- end
41
-
42
- def process_nonce
43
- @@process_nonce ||= SecureRandom.hex(6)
44
- end
45
-
46
- def identity
47
- @@identity ||= "#{hostname}:#{$$}:#{process_nonce}"
48
- end
49
-
50
- def fire_event(event, reverse=false)
51
- arr = Sidekiq.options[:lifecycle_events][event]
52
- arr.reverse! if reverse
53
- arr.each do |block|
54
- begin
55
- block.call
56
- rescue => ex
57
- handle_exception(ex, { context: "Exception during Sidekiq lifecycle event.", event: event })
58
- end
59
- end
60
- arr.clear
61
- end
62
- end
63
- end
@@ -1,121 +0,0 @@
1
- # frozen_string_literal: true
2
- require 'sidekiq/client'
3
- require 'sidekiq/core_ext'
4
-
5
- module Sidekiq
6
-
7
- ##
8
- # Include this module in your worker class and you can easily create
9
- # asynchronous jobs:
10
- #
11
- # class HardWorker
12
- # include Sidekiq::Worker
13
- #
14
- # def perform(*args)
15
- # # do some work
16
- # end
17
- # end
18
- #
19
- # Then in your Rails app, you can do this:
20
- #
21
- # HardWorker.perform_async(1, 2, 3)
22
- #
23
- # Note that perform_async is a class method, perform is an instance method.
24
- module Worker
25
- attr_accessor :jid
26
-
27
- def self.included(base)
28
- raise ArgumentError, "You cannot include Sidekiq::Worker in an ActiveJob: #{base.name}" if base.ancestors.any? {|c| c.name == 'ActiveJob::Base' }
29
-
30
- base.extend(ClassMethods)
31
- base.class_attribute :sidekiq_options_hash
32
- base.class_attribute :sidekiq_retry_in_block
33
- base.class_attribute :sidekiq_retries_exhausted_block
34
- end
35
-
36
- def logger
37
- Sidekiq.logger
38
- end
39
-
40
- module ClassMethods
41
-
42
- def delay(*args)
43
- raise ArgumentError, "Do not call .delay on a Sidekiq::Worker class, call .perform_async"
44
- end
45
-
46
- def delay_for(*args)
47
- raise ArgumentError, "Do not call .delay_for on a Sidekiq::Worker class, call .perform_in"
48
- end
49
-
50
- def delay_until(*args)
51
- raise ArgumentError, "Do not call .delay_until on a Sidekiq::Worker class, call .perform_at"
52
- end
53
-
54
- def set(options)
55
- Thread.current[:sidekiq_worker_set] = options
56
- self
57
- end
58
-
59
- def perform_async(*args)
60
- client_push('class' => self, 'args' => args)
61
- end
62
-
63
- # +interval+ must be a timestamp, numeric or something that acts
64
- # numeric (like an activesupport time interval).
65
- def perform_in(interval, *args)
66
- int = interval.to_f
67
- now = Time.now.to_f
68
- ts = (int < 1_000_000_000 ? now + int : int)
69
-
70
- item = { 'class' => self, 'args' => args, 'at' => ts }
71
-
72
- # Optimization to enqueue something now that is scheduled to go out now or in the past
73
- item.delete('at'.freeze) if ts <= now
74
-
75
- client_push(item)
76
- end
77
- alias_method :perform_at, :perform_in
78
-
79
- ##
80
- # Allows customization for this type of Worker.
81
- # Legal options:
82
- #
83
- # queue - use a named queue for this Worker, default 'default'
84
- # retry - enable the RetryJobs middleware for this Worker, *true* to use the default
85
- # or *Integer* count
86
- # backtrace - whether to save any error backtrace in the retry payload to display in web UI,
87
- # can be true, false or an integer number of lines to save, default *false*
88
- # pool - use the given Redis connection pool to push this type of job to a given shard.
89
- #
90
- # In practice, any option is allowed. This is the main mechanism to configure the
91
- # options for a specific job.
92
- def sidekiq_options(opts={})
93
- self.sidekiq_options_hash = get_sidekiq_options.merge(opts.stringify_keys)
94
- end
95
-
96
- def sidekiq_retry_in(&block)
97
- self.sidekiq_retry_in_block = block
98
- end
99
-
100
- def sidekiq_retries_exhausted(&block)
101
- self.sidekiq_retries_exhausted_block = block
102
- end
103
-
104
- def get_sidekiq_options # :nodoc:
105
- self.sidekiq_options_hash ||= Sidekiq.default_worker_options
106
- end
107
-
108
- def client_push(item) # :nodoc:
109
- pool = Thread.current[:sidekiq_via_pool] || get_sidekiq_options['pool'] || Sidekiq.redis_pool
110
- hash = if Thread.current[:sidekiq_worker_set]
111
- x, Thread.current[:sidekiq_worker_set] = Thread.current[:sidekiq_worker_set], nil
112
- x.stringify_keys.merge(item.stringify_keys)
113
- else
114
- item.stringify_keys
115
- end
116
- Sidekiq::Client.new(pool).push(hash)
117
- end
118
-
119
- end
120
- end
121
- end