sidekiq 4.1.4 → 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 (134) hide show
  1. checksums.yaml +4 -4
  2. data/.github/issue_template.md +6 -1
  3. data/.travis.yml +9 -9
  4. data/Changes.md +100 -0
  5. data/Ent-Changes.md +51 -1
  6. data/Gemfile +6 -6
  7. data/Pro-Changes.md +69 -0
  8. data/README.md +4 -3
  9. data/Rakefile +5 -2
  10. data/bin/sidekiqload +11 -24
  11. data/lib/generators/sidekiq/templates/worker_test.rb.erb +1 -1
  12. data/lib/sidekiq/api.rb +21 -13
  13. data/lib/sidekiq/cli.rb +19 -5
  14. data/lib/sidekiq/core_ext.rb +13 -0
  15. data/lib/sidekiq/launcher.rb +36 -23
  16. data/lib/sidekiq/manager.rb +3 -2
  17. data/lib/sidekiq/middleware/server/logging.rb +8 -17
  18. data/lib/sidekiq/middleware/server/retry_jobs.rb +1 -1
  19. data/lib/sidekiq/processor.rb +31 -16
  20. data/lib/sidekiq/rails.rb +84 -0
  21. data/lib/sidekiq/redis_connection.rb +8 -1
  22. data/lib/sidekiq/scheduled.rb +1 -0
  23. data/lib/sidekiq/testing.rb +10 -2
  24. data/lib/sidekiq/util.rb +2 -1
  25. data/lib/sidekiq/version.rb +1 -1
  26. data/lib/sidekiq/web/action.rb +93 -0
  27. data/lib/sidekiq/web/application.rb +336 -0
  28. data/lib/sidekiq/{web_helpers.rb → web/helpers.rb} +39 -16
  29. data/lib/sidekiq/web/router.rb +100 -0
  30. data/lib/sidekiq/web.rb +119 -184
  31. data/lib/sidekiq/worker.rb +3 -3
  32. data/lib/sidekiq.rb +7 -7
  33. data/sidekiq.gemspec +11 -5
  34. data/web/assets/images/{status-sd8051fd480.png → status.png} +0 -0
  35. data/web/assets/javascripts/application.js +24 -20
  36. data/web/assets/javascripts/dashboard.js +1 -1
  37. data/web/assets/stylesheets/application.css +26 -1
  38. data/web/assets/stylesheets/bootstrap.css +4 -8
  39. data/web/locales/de.yml +1 -1
  40. data/web/locales/fa.yml +79 -0
  41. data/web/views/_footer.erb +1 -1
  42. data/web/views/_job_info.erb +1 -1
  43. data/web/views/busy.erb +2 -2
  44. data/web/views/dashboard.erb +4 -4
  45. data/web/views/dead.erb +1 -1
  46. data/web/views/layout.erb +3 -4
  47. data/web/views/morgue.erb +14 -10
  48. data/web/views/queue.erb +6 -6
  49. data/web/views/queues.erb +3 -3
  50. data/web/views/retries.erb +12 -10
  51. data/web/views/retry.erb +2 -2
  52. data/web/views/scheduled.erb +2 -2
  53. data/web/views/scheduled_job_info.erb +1 -1
  54. metadata +86 -129
  55. data/test/config.yml +0 -9
  56. data/test/env_based_config.yml +0 -11
  57. data/test/fake_env.rb +0 -1
  58. data/test/fixtures/en.yml +0 -2
  59. data/test/helper.rb +0 -75
  60. data/test/test_actors.rb +0 -138
  61. data/test/test_api.rb +0 -528
  62. data/test/test_cli.rb +0 -406
  63. data/test/test_client.rb +0 -266
  64. data/test/test_exception_handler.rb +0 -56
  65. data/test/test_extensions.rb +0 -127
  66. data/test/test_fetch.rb +0 -50
  67. data/test/test_launcher.rb +0 -85
  68. data/test/test_logging.rb +0 -35
  69. data/test/test_manager.rb +0 -50
  70. data/test/test_middleware.rb +0 -158
  71. data/test/test_processor.rb +0 -201
  72. data/test/test_rails.rb +0 -22
  73. data/test/test_redis_connection.rb +0 -132
  74. data/test/test_retry.rb +0 -326
  75. data/test/test_retry_exhausted.rb +0 -149
  76. data/test/test_scheduled.rb +0 -115
  77. data/test/test_scheduling.rb +0 -50
  78. data/test/test_sidekiq.rb +0 -107
  79. data/test/test_testing.rb +0 -143
  80. data/test/test_testing_fake.rb +0 -357
  81. data/test/test_testing_inline.rb +0 -94
  82. data/test/test_util.rb +0 -13
  83. data/test/test_web.rb +0 -614
  84. data/test/test_web_helpers.rb +0 -54
  85. data/web/assets/images/bootstrap/glyphicons-halflings-white.png +0 -0
  86. data/web/assets/images/bootstrap/glyphicons-halflings.png +0 -0
  87. data/web/assets/images/status/active.png +0 -0
  88. data/web/assets/images/status/idle.png +0 -0
  89. data/web/assets/javascripts/locales/README.md +0 -27
  90. data/web/assets/javascripts/locales/jquery.timeago.ar.js +0 -96
  91. data/web/assets/javascripts/locales/jquery.timeago.bg.js +0 -18
  92. data/web/assets/javascripts/locales/jquery.timeago.bs.js +0 -49
  93. data/web/assets/javascripts/locales/jquery.timeago.ca.js +0 -18
  94. data/web/assets/javascripts/locales/jquery.timeago.cs.js +0 -18
  95. data/web/assets/javascripts/locales/jquery.timeago.cy.js +0 -20
  96. data/web/assets/javascripts/locales/jquery.timeago.da.js +0 -18
  97. data/web/assets/javascripts/locales/jquery.timeago.de.js +0 -18
  98. data/web/assets/javascripts/locales/jquery.timeago.el.js +0 -18
  99. data/web/assets/javascripts/locales/jquery.timeago.en-short.js +0 -20
  100. data/web/assets/javascripts/locales/jquery.timeago.en.js +0 -20
  101. data/web/assets/javascripts/locales/jquery.timeago.es.js +0 -18
  102. data/web/assets/javascripts/locales/jquery.timeago.et.js +0 -18
  103. data/web/assets/javascripts/locales/jquery.timeago.fa.js +0 -22
  104. data/web/assets/javascripts/locales/jquery.timeago.fi.js +0 -28
  105. data/web/assets/javascripts/locales/jquery.timeago.fr-short.js +0 -16
  106. data/web/assets/javascripts/locales/jquery.timeago.fr.js +0 -17
  107. data/web/assets/javascripts/locales/jquery.timeago.he.js +0 -18
  108. data/web/assets/javascripts/locales/jquery.timeago.hr.js +0 -49
  109. data/web/assets/javascripts/locales/jquery.timeago.hu.js +0 -18
  110. data/web/assets/javascripts/locales/jquery.timeago.hy.js +0 -18
  111. data/web/assets/javascripts/locales/jquery.timeago.id.js +0 -18
  112. data/web/assets/javascripts/locales/jquery.timeago.it.js +0 -16
  113. data/web/assets/javascripts/locales/jquery.timeago.ja.js +0 -19
  114. data/web/assets/javascripts/locales/jquery.timeago.ko.js +0 -17
  115. data/web/assets/javascripts/locales/jquery.timeago.lt.js +0 -20
  116. data/web/assets/javascripts/locales/jquery.timeago.mk.js +0 -20
  117. data/web/assets/javascripts/locales/jquery.timeago.nb.js +0 -18
  118. data/web/assets/javascripts/locales/jquery.timeago.nl.js +0 -20
  119. data/web/assets/javascripts/locales/jquery.timeago.pl.js +0 -31
  120. data/web/assets/javascripts/locales/jquery.timeago.pt-br.js +0 -16
  121. data/web/assets/javascripts/locales/jquery.timeago.pt.js +0 -16
  122. data/web/assets/javascripts/locales/jquery.timeago.ro.js +0 -18
  123. data/web/assets/javascripts/locales/jquery.timeago.rs.js +0 -49
  124. data/web/assets/javascripts/locales/jquery.timeago.ru.js +0 -34
  125. data/web/assets/javascripts/locales/jquery.timeago.sk.js +0 -18
  126. data/web/assets/javascripts/locales/jquery.timeago.sl.js +0 -44
  127. data/web/assets/javascripts/locales/jquery.timeago.sv.js +0 -18
  128. data/web/assets/javascripts/locales/jquery.timeago.th.js +0 -20
  129. data/web/assets/javascripts/locales/jquery.timeago.tr.js +0 -16
  130. data/web/assets/javascripts/locales/jquery.timeago.uk.js +0 -34
  131. data/web/assets/javascripts/locales/jquery.timeago.uz.js +0 -19
  132. data/web/assets/javascripts/locales/jquery.timeago.zh-cn.js +0 -20
  133. data/web/assets/javascripts/locales/jquery.timeago.zh-tw.js +0 -20
  134. data/web/views/_poll_js.erb +0 -5
@@ -1,5 +1,5 @@
1
- # frozen_string_literal: true
2
1
  # encoding: utf-8
2
+ # frozen_string_literal: true
3
3
  require 'sidekiq/manager'
4
4
  require 'sidekiq/fetch'
5
5
  require 'sidekiq/scheduled'
@@ -63,15 +63,16 @@ module Sidekiq
63
63
 
64
64
  JVM_RESERVED_SIGNALS = ['USR1', 'USR2'] # Don't Process#kill if we get these signals via the API
65
65
 
66
- def heartbeat(k, data, json)
67
- results = Sidekiq::CLI::PROCTITLES.map {|x| x.(self, data) }
66
+ def heartbeat
67
+ results = Sidekiq::CLI::PROCTITLES.map {|x| x.(self, to_data) }
68
68
  results.compact!
69
69
  $0 = results.join(' ')
70
70
 
71
- (k, json)
71
+
72
72
  end
73
73
 
74
- def ❤(key, json)
74
+ def ❤
75
+ key = identity
75
76
  fails = procd = 0
76
77
  begin
77
78
  Processor::FAILURE.update {|curr| fails = curr; 0 }
@@ -94,15 +95,19 @@ module Sidekiq
94
95
  end
95
96
  fails = procd = 0
96
97
 
97
- _, _, _, msg = Sidekiq.redis do |conn|
98
+ _, exists, _, _, msg = Sidekiq.redis do |conn|
98
99
  conn.multi do
99
100
  conn.sadd('processes', key)
100
- conn.hmset(key, 'info', json, 'busy', Processor::WORKER_STATE.size, 'beat', Time.now.to_f, 'quiet', @done)
101
+ conn.exists(key)
102
+ conn.hmset(key, 'info', to_json, 'busy', Processor::WORKER_STATE.size, 'beat', Time.now.to_f, 'quiet', @done)
101
103
  conn.expire(key, 60)
102
104
  conn.rpop("#{key}-signals")
103
105
  end
104
106
  end
105
107
 
108
+ # first heartbeat or recovering from an outage and need to reestablish our heartbeat
109
+ fire_event(:heartbeat) if !exists
110
+
106
111
  return unless msg
107
112
 
108
113
  if JVM_RESERVED_SIGNALS.include?(msg)
@@ -120,28 +125,36 @@ module Sidekiq
120
125
  end
121
126
 
122
127
  def start_heartbeat
123
- k = identity
124
- data = {
125
- 'hostname' => hostname,
126
- 'started_at' => Time.now.to_f,
127
- 'pid' => $$,
128
- 'tag' => @options[:tag] || '',
129
- 'concurrency' => @options[:concurrency],
130
- 'queues' => @options[:queues].uniq,
131
- 'labels' => @options[:labels],
132
- 'identity' => k,
133
- }
134
- # this data doesn't change so dump it to a string
135
- # now so we don't need to dump it every heartbeat.
136
- json = Sidekiq.dump_json(data)
137
-
138
128
  while true
139
- heartbeat(k, data, json)
129
+ heartbeat
140
130
  sleep 5
141
131
  end
142
132
  Sidekiq.logger.info("Heartbeat stopping...")
143
133
  end
144
134
 
135
+ def to_data
136
+ @data ||= begin
137
+ {
138
+ 'hostname' => hostname,
139
+ 'started_at' => Time.now.to_f,
140
+ 'pid' => $$,
141
+ 'tag' => @options[:tag] || '',
142
+ 'concurrency' => @options[:concurrency],
143
+ 'queues' => @options[:queues].uniq,
144
+ 'labels' => @options[:labels],
145
+ 'identity' => identity,
146
+ }
147
+ end
148
+ end
149
+
150
+ def to_json
151
+ @json ||= begin
152
+ # this data changes infrequently so dump it to a string
153
+ # now so we don't need to dump it every heartbeat.
154
+ Sidekiq.dump_json(to_data)
155
+ end
156
+ end
157
+
145
158
  def clear_heartbeat
146
159
  # Remove record from Redis since we are shutting down.
147
160
  # Note we don't stop the heartbeat thread; if the process
@@ -1,15 +1,16 @@
1
- # frozen_string_literal: true
2
1
  # encoding: utf-8
2
+ # frozen_string_literal: true
3
3
  require 'sidekiq/util'
4
4
  require 'sidekiq/processor'
5
5
  require 'sidekiq/fetch'
6
6
  require 'thread'
7
+ require 'set'
7
8
 
8
9
  module Sidekiq
9
10
 
10
11
  ##
11
12
  # The Manager is the central coordination point in Sidekiq, controlling
12
- # the lifecycle of the Processors and feeding them jobs as necessary.
13
+ # the lifecycle of the Processors.
13
14
  #
14
15
  # Tasks:
15
16
  #
@@ -4,28 +4,19 @@ module Sidekiq
4
4
  class Logging
5
5
 
6
6
  def call(worker, item, queue)
7
- Sidekiq::Logging.with_context(log_context(worker, item)) do
8
- begin
9
- start = Time.now
10
- logger.info("start".freeze)
11
- yield
12
- logger.info("done: #{elapsed(start)} sec")
13
- rescue Exception
14
- logger.info("fail: #{elapsed(start)} sec")
15
- raise
16
- end
7
+ begin
8
+ start = Time.now
9
+ logger.info("start".freeze)
10
+ yield
11
+ logger.info("done: #{elapsed(start)} sec")
12
+ rescue Exception
13
+ logger.info("fail: #{elapsed(start)} sec")
14
+ raise
17
15
  end
18
16
  end
19
17
 
20
18
  private
21
19
 
22
- # If we're using a wrapper class, like ActiveJob, use the "wrapped"
23
- # attribute to expose the underlying thing.
24
- def log_context(worker, item)
25
- klass = item['wrapped'.freeze] || worker.class.to_s
26
- "#{klass} JID-#{item['jid'.freeze]}#{" BID-#{item['bid'.freeze]}" if item['bid'.freeze]}"
27
- end
28
-
29
20
  def elapsed(start)
30
21
  (Time.now - start).round(3)
31
22
  end
@@ -162,7 +162,7 @@ module Sidekiq
162
162
  end
163
163
 
164
164
  def retry_attempts_from(msg_retry, default)
165
- if msg_retry.is_a?(Fixnum)
165
+ if msg_retry.is_a?(Integer)
166
166
  msg_retry
167
167
  else
168
168
  default
@@ -36,6 +36,8 @@ module Sidekiq
36
36
  @job = nil
37
37
  @thread = nil
38
38
  @strategy = (mgr.options[:fetch] || Sidekiq::BasicFetch).new(mgr.options)
39
+ @reloader = Sidekiq.options[:reloader]
40
+ @executor = Sidekiq.options[:executor]
39
41
  end
40
42
 
41
43
  def terminate(wait=false)
@@ -120,34 +122,47 @@ module Sidekiq
120
122
 
121
123
  ack = false
122
124
  begin
123
- job = Sidekiq.load_json(jobstr)
124
- klass = job['class'.freeze].constantize
125
- worker = klass.new
126
- worker.jid = job['jid'.freeze]
127
-
128
- stats(worker, job, queue) do
129
- Sidekiq.server_middleware.invoke(worker, job, queue) do
130
- # Only ack if we either attempted to start this job or
131
- # successfully completed it. This prevents us from
132
- # losing jobs if a middleware raises an exception before yielding
133
- ack = true
134
- execute_job(worker, cloned(job['args'.freeze]))
125
+ job_hash = Sidekiq.load_json(jobstr)
126
+ @reloader.call do
127
+ klass = job_hash['class'.freeze].constantize
128
+ worker = klass.new
129
+ worker.jid = job_hash['jid'.freeze]
130
+
131
+ stats(worker, job_hash, queue) do
132
+ Sidekiq::Logging.with_context(log_context(job_hash)) do
133
+ ack = true
134
+ Sidekiq.server_middleware.invoke(worker, job_hash, queue) do
135
+ @executor.call do
136
+ # Only ack if we either attempted to start this job or
137
+ # successfully completed it. This prevents us from
138
+ # losing jobs if a middleware raises an exception before yielding
139
+ execute_job(worker, cloned(job_hash['args'.freeze]))
140
+ end
141
+ end
142
+ end
135
143
  end
144
+ ack = true
136
145
  end
137
- ack = true
138
146
  rescue Sidekiq::Shutdown
139
147
  # Had to force kill this job because it didn't finish
140
148
  # within the timeout. Don't acknowledge the work since
141
149
  # we didn't properly finish it.
142
150
  ack = false
143
151
  rescue Exception => ex
144
- handle_exception(ex, job || { :job => jobstr })
152
+ handle_exception(ex, { :context => "Job raised exception", :job => job_hash, :jobstr => jobstr })
145
153
  raise
146
154
  ensure
147
155
  work.acknowledge if ack
148
156
  end
149
157
  end
150
158
 
159
+ # If we're using a wrapper class, like ActiveJob, use the "wrapped"
160
+ # attribute to expose the underlying thing.
161
+ def log_context(item)
162
+ klass = item['wrapped'.freeze] || item['class'.freeze]
163
+ "#{klass} JID-#{item['jid'.freeze]}#{" BID-#{item['bid'.freeze]}" if item['bid'.freeze]}"
164
+ end
165
+
151
166
  def execute_job(worker, cloned_args)
152
167
  worker.perform(*cloned_args)
153
168
  end
@@ -160,9 +175,9 @@ module Sidekiq
160
175
  PROCESSED = Concurrent::AtomicFixnum.new
161
176
  FAILURE = Concurrent::AtomicFixnum.new
162
177
 
163
- def stats(worker, job, queue)
178
+ def stats(worker, job_hash, queue)
164
179
  tid = thread_identity
165
- WORKER_STATE[tid] = {:queue => queue, :payload => job, :run_at => Time.now.to_i }
180
+ WORKER_STATE[tid] = {:queue => queue, :payload => cloned(job_hash), :run_at => Time.now.to_i }
166
181
 
167
182
  begin
168
183
  yield
data/lib/sidekiq/rails.rb CHANGED
@@ -32,8 +32,92 @@ module Sidekiq
32
32
  end
33
33
 
34
34
  class Rails < ::Rails::Engine
35
+ # We need to setup this up before any application configuration which might
36
+ # change Sidekiq middleware.
37
+ #
38
+ # This hook happens after `Rails::Application` is inherited within
39
+ # config/application.rb and before config is touched, usually within the
40
+ # class block. Definitely before config/environments/*.rb and
41
+ # config/initializers/*.rb.
42
+ config.before_configuration do
43
+ if ::Rails::VERSION::MAJOR < 5 && defined?(::ActiveRecord)
44
+ Sidekiq.server_middleware do |chain|
45
+ require 'sidekiq/middleware/server/active_record'
46
+ chain.add Sidekiq::Middleware::Server::ActiveRecord
47
+ end
48
+ end
49
+ end
50
+
35
51
  initializer 'sidekiq' do
36
52
  Sidekiq.hook_rails!
37
53
  end
54
+
55
+ config.after_initialize do
56
+ # This hook happens after all initializers are run, just before returning
57
+ # from config/environment.rb back to sidekiq/cli.rb.
58
+ # We have to add the reloader after initialize to see if cache_classes has
59
+ # been turned on.
60
+ #
61
+ # None of this matters on the client-side, only within the Sidekiq process itself.
62
+ #
63
+ Sidekiq.configure_server do |_|
64
+ if ::Rails::VERSION::MAJOR >= 5
65
+ # The reloader also takes care of ActiveRecord but is incompatible with
66
+ # the ActiveRecord middleware so make sure it's not in the chain already.
67
+ if defined?(Sidekiq::Middleware::Server::ActiveRecord) && Sidekiq.server_middleware.exists?(Sidekiq::Middleware::Server::ActiveRecord)
68
+ raise ArgumentError, "You are using the Sidekiq ActiveRecord middleware and the new Rails 5 reloader which are incompatible. Please remove the ActiveRecord middleware from your Sidekiq middleware configuration."
69
+ elsif ::Rails.application.config.cache_classes
70
+ # The reloader API has proven to be troublesome under load in production.
71
+ # We won't use it at all when classes are cached, see #3154
72
+ Sidekiq.logger.debug { "Autoload disabled in #{::Rails.env}, Sidekiq will not reload changed classes" }
73
+ Sidekiq.options[:executor] = Sidekiq::Rails::Executor.new
74
+ else
75
+ Sidekiq.logger.debug { "Enabling Rails 5+ live code reloading, so hot!" }
76
+ Sidekiq.options[:reloader] = Sidekiq::Rails::Reloader.new
77
+ Psych::Visitors::ToRuby.prepend(Sidekiq::Rails::PsychAutoload)
78
+ end
79
+ end
80
+ end
81
+ end
82
+
83
+ class Executor
84
+ def initialize(app = ::Rails.application)
85
+ @app = app
86
+ end
87
+
88
+ def call
89
+ @app.executor.wrap do
90
+ yield
91
+ end
92
+ end
93
+
94
+ def inspect
95
+ "#<Sidekiq::Rails::Executor @app=#{@app.class.name}>"
96
+ end
97
+ end
98
+
99
+ class Reloader
100
+ def initialize(app = ::Rails.application)
101
+ @app = app
102
+ end
103
+
104
+ def call
105
+ @app.reloader.wrap do
106
+ yield
107
+ end
108
+ end
109
+
110
+ def inspect
111
+ "#<Sidekiq::Rails::Reloader @app=#{@app.class.name}>"
112
+ end
113
+ end
114
+
115
+ module PsychAutoload
116
+ def resolve_class(klass_name)
117
+ klass_name && klass_name.constantize
118
+ rescue NameError
119
+ super
120
+ end
121
+ end
38
122
  end if defined?(::Rails)
39
123
  end
@@ -67,7 +67,14 @@ module Sidekiq
67
67
  opts.delete(:network_timeout)
68
68
  end
69
69
 
70
- opts[:driver] = opts[:driver] || 'ruby'
70
+ opts[:driver] ||= 'ruby'
71
+
72
+ # Issue #3303, redis-rb will silently retry an operation.
73
+ # This can lead to duplicate jobs if Sidekiq::Client's LPUSH
74
+ # is performed twice but I believe this is much, much rarer
75
+ # than the reconnect silently fixing a problem; we keep it
76
+ # on by default.
77
+ opts[:reconnect_attempts] ||= 1
71
78
 
72
79
  opts
73
80
  end
@@ -46,6 +46,7 @@ module Sidekiq
46
46
  @enq = (Sidekiq.options[:scheduled_enq] || Sidekiq::Scheduled::Enq).new
47
47
  @sleeper = ConnectionPool::TimedStack.new
48
48
  @done = false
49
+ @thread = nil
49
50
  end
50
51
 
51
52
  # Shut down this instance, will pause until the thread is dead.
@@ -69,7 +69,9 @@ module Sidekiq
69
69
  def raw_push(payloads)
70
70
  if Sidekiq::Testing.fake?
71
71
  payloads.each do |job|
72
- Queues.push(job['queue'], job['class'], Sidekiq.load_json(Sidekiq.dump_json(job)))
72
+ job = Sidekiq.load_json(Sidekiq.dump_json(job))
73
+ job.merge!('enqueued_at' => Time.now.to_f) unless job['at']
74
+ Queues.push(job['queue'], job['class'], job)
73
75
  end
74
76
  true
75
77
  elsif Sidekiq::Testing.inline?
@@ -264,7 +266,7 @@ module Sidekiq
264
266
  def drain
265
267
  while jobs.any?
266
268
  next_job = jobs.first
267
- Queues.delete_for(next_job["jid"], queue, self.to_s)
269
+ Queues.delete_for(next_job["jid"], next_job["queue"], self.to_s)
268
270
  process_job(next_job)
269
271
  end
270
272
  end
@@ -314,3 +316,9 @@ module Sidekiq
314
316
  end
315
317
  end
316
318
  end
319
+
320
+ if defined?(::Rails) && !Rails.env.test?
321
+ puts("**************************************************")
322
+ puts("⛔️ WARNING: Sidekiq testing API enabled, but this is not the test environment. Your jobs will not go to Redis.")
323
+ puts("**************************************************")
324
+ end
data/lib/sidekiq/util.rb CHANGED
@@ -22,6 +22,7 @@ module Sidekiq
22
22
 
23
23
  def safe_thread(name, &block)
24
24
  Thread.new do
25
+ Thread.current['sidekiq_label'] = name
25
26
  watchdog(name, &block)
26
27
  end
27
28
  end
@@ -53,7 +54,7 @@ module Sidekiq
53
54
  begin
54
55
  block.call
55
56
  rescue => ex
56
- handle_exception(ex, { event: event })
57
+ handle_exception(ex, { context: "Exception during Sidekiq lifecycle event.", event: event })
57
58
  end
58
59
  end
59
60
  arr.clear
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module Sidekiq
3
- VERSION = "4.1.4"
3
+ VERSION = "4.2.10"
4
4
  end
@@ -0,0 +1,93 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sidekiq
4
+ class WebAction
5
+ RACK_SESSION = 'rack.session'.freeze
6
+
7
+ attr_accessor :env, :block, :type
8
+
9
+ def settings
10
+ Web.settings
11
+ end
12
+
13
+ def request
14
+ @request ||= ::Rack::Request.new(env)
15
+ end
16
+
17
+ def halt(res)
18
+ throw :halt, res
19
+ end
20
+
21
+ def redirect(location)
22
+ throw :halt, [302, { "Location" => "#{request.base_url}#{location}" }, []]
23
+ end
24
+
25
+ def params
26
+ indifferent_hash = Hash.new {|hash,key| hash[key.to_s] if Symbol === key }
27
+
28
+ indifferent_hash.merge! request.params
29
+ route_params.each {|k,v| indifferent_hash[k.to_s] = v }
30
+
31
+ indifferent_hash
32
+ end
33
+
34
+ def route_params
35
+ env[WebRouter::ROUTE_PARAMS]
36
+ end
37
+
38
+ def session
39
+ env[RACK_SESSION]
40
+ end
41
+
42
+ def content_type(type)
43
+ @type = type
44
+ end
45
+
46
+ def erb(content, options = {})
47
+ if content.kind_of? Symbol
48
+ unless respond_to?(:"_erb_#{content}")
49
+ src = ERB.new(File.read("#{Web.settings.views}/#{content}.erb")).src
50
+ WebAction.class_eval("def _erb_#{content}\n#{src}\n end")
51
+ end
52
+ end
53
+
54
+ if @_erb
55
+ _erb(content, options[:locals])
56
+ else
57
+ @_erb = true
58
+ content = _erb(content, options[:locals])
59
+
60
+ _render { content }
61
+ end
62
+ end
63
+
64
+ def render(engine, content, options = {})
65
+ raise "Only erb templates are supported" if engine != :erb
66
+
67
+ erb(content, options)
68
+ end
69
+
70
+ def json(payload)
71
+ [200, { "Content-Type" => "application/json", "Cache-Control" => "no-cache" }, [Sidekiq.dump_json(payload)]]
72
+ end
73
+
74
+ def initialize(env, block)
75
+ @_erb = false
76
+ @env = env
77
+ @block = block
78
+ @@files ||= {}
79
+ end
80
+
81
+ private
82
+
83
+ def _erb(file, locals)
84
+ locals.each {|k, v| define_singleton_method(k){ v } } if locals
85
+
86
+ if file.kind_of?(String)
87
+ ERB.new(file).result(binding)
88
+ else
89
+ send(:"_erb_#{file}")
90
+ end
91
+ end
92
+ end
93
+ end