sidekiq 3.4.1 → 4.0.2

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 (88) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +3 -2
  3. data/4.0-Upgrade.md +50 -0
  4. data/COMM-LICENSE +55 -45
  5. data/Changes.md +85 -1
  6. data/Ent-Changes.md +79 -0
  7. data/Gemfile +7 -1
  8. data/Pro-2.0-Upgrade.md +2 -2
  9. data/Pro-3.0-Upgrade.md +46 -0
  10. data/Pro-Changes.md +60 -2
  11. data/README.md +20 -16
  12. data/bin/sidekiq +4 -0
  13. data/bin/sidekiqctl +8 -2
  14. data/bin/sidekiqload +167 -0
  15. data/lib/generators/sidekiq/templates/worker_spec.rb.erb +2 -2
  16. data/lib/generators/sidekiq/templates/worker_test.rb.erb +5 -5
  17. data/lib/sidekiq/api.rb +43 -33
  18. data/lib/sidekiq/cli.rb +41 -42
  19. data/lib/sidekiq/client.rb +5 -10
  20. data/lib/sidekiq/fetch.rb +35 -111
  21. data/lib/sidekiq/launcher.rb +102 -42
  22. data/lib/sidekiq/manager.rb +80 -180
  23. data/lib/sidekiq/middleware/server/logging.rb +13 -8
  24. data/lib/sidekiq/middleware/server/retry_jobs.rb +6 -6
  25. data/lib/sidekiq/processor.rb +126 -97
  26. data/lib/sidekiq/redis_connection.rb +23 -5
  27. data/lib/sidekiq/scheduled.rb +47 -26
  28. data/lib/sidekiq/testing.rb +139 -17
  29. data/lib/sidekiq/util.rb +20 -0
  30. data/lib/sidekiq/version.rb +1 -1
  31. data/lib/sidekiq/web.rb +17 -1
  32. data/lib/sidekiq/web_helpers.rb +33 -5
  33. data/lib/sidekiq/worker.rb +16 -0
  34. data/lib/sidekiq.rb +37 -14
  35. data/sidekiq.gemspec +10 -11
  36. data/test/helper.rb +45 -10
  37. data/test/test_actors.rb +137 -0
  38. data/test/test_api.rb +417 -384
  39. data/test/test_cli.rb +29 -59
  40. data/test/test_client.rb +60 -135
  41. data/test/test_extensions.rb +29 -23
  42. data/test/test_fetch.rb +2 -57
  43. data/test/test_launcher.rb +80 -0
  44. data/test/test_logging.rb +1 -1
  45. data/test/test_manager.rb +16 -131
  46. data/test/test_middleware.rb +3 -5
  47. data/test/test_processor.rb +110 -76
  48. data/test/test_rails.rb +21 -0
  49. data/test/test_redis_connection.rb +0 -1
  50. data/test/test_retry.rb +114 -162
  51. data/test/test_scheduled.rb +11 -17
  52. data/test/test_scheduling.rb +20 -42
  53. data/test/test_sidekiq.rb +46 -16
  54. data/test/test_testing.rb +80 -20
  55. data/test/test_testing_fake.rb +83 -8
  56. data/test/test_testing_inline.rb +3 -3
  57. data/test/test_util.rb +16 -0
  58. data/test/test_web.rb +28 -9
  59. data/test/test_web_helpers.rb +3 -2
  60. data/web/assets/images/favicon.ico +0 -0
  61. data/web/assets/javascripts/application.js +6 -1
  62. data/web/assets/javascripts/dashboard.js +2 -8
  63. data/web/assets/javascripts/locales/jquery.timeago.pt-br.js +14 -14
  64. data/web/assets/stylesheets/application.css +33 -56
  65. data/web/locales/de.yml +1 -1
  66. data/web/locales/en.yml +2 -0
  67. data/web/locales/fr.yml +2 -2
  68. data/web/locales/ja.yml +10 -1
  69. data/web/locales/{no.yml → nb.yml} +10 -2
  70. data/web/locales/uk.yml +76 -0
  71. data/web/views/_footer.erb +2 -7
  72. data/web/views/_job_info.erb +5 -1
  73. data/web/views/_nav.erb +2 -2
  74. data/web/views/_poll_js.erb +5 -0
  75. data/web/views/{_poll.erb → _poll_link.erb} +0 -3
  76. data/web/views/busy.erb +2 -1
  77. data/web/views/dead.erb +1 -0
  78. data/web/views/layout.erb +2 -0
  79. data/web/views/morgue.erb +3 -0
  80. data/web/views/queue.erb +1 -0
  81. data/web/views/queues.erb +1 -0
  82. data/web/views/retries.erb +3 -0
  83. data/web/views/retry.erb +1 -0
  84. data/web/views/scheduled.erb +1 -0
  85. data/web/views/scheduled_job_info.erb +1 -0
  86. metadata +75 -55
  87. data/lib/sidekiq/actor.rb +0 -39
  88. data/test/test_worker_generator.rb +0 -17
@@ -48,6 +48,12 @@ module Sidekiq
48
48
  def inline?
49
49
  self.__test_mode == :inline
50
50
  end
51
+
52
+ def server_middleware
53
+ @server_chain ||= Middleware::Chain.new
54
+ yield @server_chain if block_given?
55
+ @server_chain
56
+ end
51
57
  end
52
58
  end
53
59
 
@@ -62,15 +68,15 @@ module Sidekiq
62
68
  def raw_push(payloads)
63
69
  if Sidekiq::Testing.fake?
64
70
  payloads.each do |job|
65
- job['class'].constantize.jobs << Sidekiq.load_json(Sidekiq.dump_json(job))
71
+ Queues.push(job['queue'], job['class'], Sidekiq.load_json(Sidekiq.dump_json(job)))
66
72
  end
67
73
  true
68
74
  elsif Sidekiq::Testing.inline?
69
75
  payloads.each do |job|
70
- job['jid'] ||= SecureRandom.hex(12)
71
76
  klass = job['class'].constantize
72
- klass.jobs.unshift Sidekiq.load_json(Sidekiq.dump_json(job))
73
- klass.perform_one
77
+ job['id'] ||= SecureRandom.hex(12)
78
+ job_hash = Sidekiq.load_json(Sidekiq.dump_json(job))
79
+ klass.process_job(job_hash)
74
80
  end
75
81
  true
76
82
  else
@@ -79,6 +85,107 @@ module Sidekiq
79
85
  end
80
86
  end
81
87
 
88
+ module Queues
89
+ ##
90
+ # The Queues class is only for testing the fake queue implementation.
91
+ # There are 2 data structures involved in tandem. This is due to the
92
+ # Rspec syntax of change(QueueWorker.jobs, :size). It keeps a reference
93
+ # to the array. Because the array was dervied from a filter of the total
94
+ # jobs enqueued, it appeared as though the array didn't change.
95
+ #
96
+ # To solve this, we'll keep 2 hashes containing the jobs. One with keys based
97
+ # on the queue, and another with keys of the worker names, so the array for
98
+ # QueueWorker.jobs is a straight reference to a real array.
99
+ #
100
+ # Queue-based hash:
101
+ #
102
+ # {
103
+ # "default"=>[
104
+ # {
105
+ # "class"=>"TestTesting::QueueWorker",
106
+ # "args"=>[1, 2],
107
+ # "retry"=>true,
108
+ # "queue"=>"default",
109
+ # "jid"=>"abc5b065c5c4b27fc1102833",
110
+ # "created_at"=>1447445554.419934
111
+ # }
112
+ # ]
113
+ # }
114
+ #
115
+ # Worker-based hash:
116
+ #
117
+ # {
118
+ # "TestTesting::QueueWorker"=>[
119
+ # {
120
+ # "class"=>"TestTesting::QueueWorker",
121
+ # "args"=>[1, 2],
122
+ # "retry"=>true,
123
+ # "queue"=>"default",
124
+ # "jid"=>"abc5b065c5c4b27fc1102833",
125
+ # "created_at"=>1447445554.419934
126
+ # }
127
+ # ]
128
+ # }
129
+ #
130
+ # Example:
131
+ #
132
+ # require 'sidekiq/testing'
133
+ #
134
+ # assert_equal 0, Sidekiq::Queues["default"].size
135
+ # HardWorker.perform_async(:something)
136
+ # assert_equal 1, Sidekiq::Queues["default"].size
137
+ # assert_equal :something, Sidekiq::Queues["default"].first['args'][0]
138
+ #
139
+ # You can also clear all workers' jobs:
140
+ #
141
+ # assert_equal 0, Sidekiq::Queues["default"].size
142
+ # HardWorker.perform_async(:something)
143
+ # Sidekiq::Queues.clear_all
144
+ # assert_equal 0, Sidekiq::Queues["default"].size
145
+ #
146
+ # This can be useful to make sure jobs don't linger between tests:
147
+ #
148
+ # RSpec.configure do |config|
149
+ # config.before(:each) do
150
+ # Sidekiq::Queues.clear_all
151
+ # end
152
+ # end
153
+ #
154
+ class << self
155
+ def [](queue)
156
+ jobs_by_queue[queue]
157
+ end
158
+
159
+ def push(queue, klass, job)
160
+ jobs_by_queue[queue] << job
161
+ jobs_by_worker[klass] << job
162
+ end
163
+
164
+ def jobs_by_queue
165
+ @jobs_by_queue ||= Hash.new { |hash, key| hash[key] = [] }
166
+ end
167
+
168
+ def jobs_by_worker
169
+ @jobs_by_worker ||= Hash.new { |hash, key| hash[key] = [] }
170
+ end
171
+
172
+ def delete_for(jid, queue, klass)
173
+ jobs_by_queue[queue].delete_if { |job| job["jid"] == jid }
174
+ jobs_by_worker[klass].delete_if { |job| job["jid"] == jid }
175
+ end
176
+
177
+ def clear_for(queue, klass)
178
+ jobs_by_queue[queue].clear
179
+ jobs_by_worker[klass].clear
180
+ end
181
+
182
+ def clear_all
183
+ jobs_by_queue.clear
184
+ jobs_by_worker.clear
185
+ end
186
+ end
187
+ end
188
+
82
189
  module Worker
83
190
  ##
84
191
  # The Sidekiq testing infrastructure overrides perform_async
@@ -137,34 +244,45 @@ module Sidekiq
137
244
  #
138
245
  module ClassMethods
139
246
 
247
+ # Queue for this worker
248
+ def queue
249
+ self.sidekiq_options["queue"]
250
+ end
251
+
140
252
  # Jobs queued for this worker
141
253
  def jobs
142
- Worker.jobs[self]
254
+ Queues.jobs_by_worker[self.to_s]
143
255
  end
144
256
 
145
257
  # Clear all jobs for this worker
146
258
  def clear
147
- jobs.clear
259
+ Queues.clear_for(queue, self.to_s)
148
260
  end
149
261
 
150
262
  # Drain and run all jobs for this worker
151
263
  def drain
152
- while job = jobs.shift do
153
- worker = new
154
- worker.jid = job['jid']
155
- worker.bid = job['bid'] if worker.respond_to?(:bid=)
156
- execute_job(worker, job['args'])
264
+ while jobs.any?
265
+ next_job = jobs.first
266
+ Queues.delete_for(next_job["jid"], queue, self.to_s)
267
+ process_job(next_job)
157
268
  end
158
269
  end
159
270
 
160
271
  # Pop out a single job and perform it
161
272
  def perform_one
162
273
  raise(EmptyQueueError, "perform_one called with empty job queue") if jobs.empty?
163
- job = jobs.shift
274
+ next_job = jobs.first
275
+ Queues.delete_for(next_job["jid"], queue, self.to_s)
276
+ process_job(next_job)
277
+ end
278
+
279
+ def process_job(job)
164
280
  worker = new
165
281
  worker.jid = job['jid']
166
282
  worker.bid = job['bid'] if worker.respond_to?(:bid=)
167
- execute_job(worker, job['args'])
283
+ Sidekiq::Testing.server_middleware.invoke(worker, job, job['queue']) do
284
+ execute_job(worker, job['args'])
285
+ end
168
286
  end
169
287
 
170
288
  def execute_job(worker, args)
@@ -174,18 +292,22 @@ module Sidekiq
174
292
 
175
293
  class << self
176
294
  def jobs # :nodoc:
177
- @jobs ||= Hash.new { |hash, key| hash[key] = [] }
295
+ Queues.jobs_by_queue.values.flatten
178
296
  end
179
297
 
180
298
  # Clear all queued jobs across all workers
181
299
  def clear_all
182
- jobs.clear
300
+ Queues.clear_all
183
301
  end
184
302
 
185
303
  # Drain all queued jobs across all workers
186
304
  def drain_all
187
- until jobs.values.all?(&:empty?) do
188
- jobs.keys.each(&:drain)
305
+ while jobs.any?
306
+ worker_classes = jobs.map { |job| job["class"] }.uniq
307
+
308
+ worker_classes.each do |worker_class|
309
+ worker_class.constantize.drain
310
+ end
189
311
  end
190
312
  end
191
313
  end
data/lib/sidekiq/util.rb CHANGED
@@ -19,6 +19,12 @@ module Sidekiq
19
19
  raise ex
20
20
  end
21
21
 
22
+ def safe_thread(name, &block)
23
+ Thread.new do
24
+ watchdog(name, &block)
25
+ end
26
+ end
27
+
22
28
  def logger
23
29
  Sidekiq.logger
24
30
  end
@@ -49,6 +55,20 @@ module Sidekiq
49
55
  handle_exception(ex, { event: event })
50
56
  end
51
57
  end
58
+ arr.clear
59
+ end
60
+
61
+ def want_a_hertz_donut?
62
+ # what's a hertz donut?
63
+ # punch! Hurts, don't it?
64
+ info = Sidekiq.redis {|c| c.info }
65
+ if info['connected_clients'].to_i > 1000 && info['hz'].to_i >= 10
66
+ Sidekiq.logger.warn { "Your Redis `hz` setting is too high at #{info['hz']}. See mperham/sidekiq#2431. Set it to 3 in #{info[:config_file]}" }
67
+ true
68
+ else
69
+ Sidekiq.logger.debug { "Redis hz: #{info['hz']}. Client count: #{info['connected_clients']}" }
70
+ false
71
+ end
52
72
  end
53
73
 
54
74
  end
@@ -1,3 +1,3 @@
1
1
  module Sidekiq
2
- VERSION = "3.4.1"
2
+ VERSION = "4.0.2"
3
3
  end
data/lib/sidekiq/web.rb CHANGED
@@ -11,6 +11,9 @@ module Sidekiq
11
11
  class Web < Sinatra::Base
12
12
  include Sidekiq::Paginator
13
13
 
14
+ enable :sessions
15
+ use ::Rack::Protection, :use => :authenticity_token unless ENV['RACK_ENV'] == 'test'
16
+
14
17
  set :root, File.expand_path(File.dirname(__FILE__) + "/../../web")
15
18
  set :public_folder, proc { "#{root}/assets" }
16
19
  set :views, proc { "#{root}/views" }
@@ -98,7 +101,7 @@ module Sidekiq
98
101
  end
99
102
 
100
103
  post '/morgue' do
101
- halt 404 unless params['key']
104
+ redirect request.path unless params['key']
102
105
 
103
106
  params['key'].each do |key|
104
107
  job = Sidekiq::DeadSet.new.fetch(*parse_params(key)).first
@@ -259,3 +262,16 @@ module Sidekiq
259
262
  end
260
263
  end
261
264
  end
265
+
266
+ if defined?(::ActionDispatch::Request::Session) &&
267
+ !::ActionDispatch::Request::Session.respond_to?(:each)
268
+ # mperham/sidekiq#2460
269
+ # Rack apps can't reuse the Rails session store without
270
+ # this monkeypatch
271
+ class ActionDispatch::Request::Session
272
+ def each(&block)
273
+ hash = self.to_hash
274
+ hash.each(&block)
275
+ end
276
+ end
277
+ end
@@ -17,8 +17,13 @@ module Sidekiq
17
17
  end
18
18
  end
19
19
 
20
+ def clear_caches
21
+ @@strings = nil
22
+ @@locale_files = nil
23
+ end
24
+
20
25
  def locale_files
21
- @@locale_files = settings.locales.flat_map do |path|
26
+ @@locale_files ||= settings.locales.flat_map do |path|
22
27
  Dir["#{path}/*.yml"]
23
28
  end
24
29
  end
@@ -45,7 +50,7 @@ module Sidekiq
45
50
  end
46
51
 
47
52
  def display_custom_head
48
- return unless @head_html
53
+ return unless defined?(@head_html)
49
54
  @head_html.map { |block| capture(&block) }.join
50
55
  end
51
56
 
@@ -160,7 +165,7 @@ module Sidekiq
160
165
  options = options.stringify_keys
161
166
  params.merge(options).map do |key, value|
162
167
  SAFE_QPARAMS.include?(key) ? "#{key}=#{value}" : next
163
- end.join("&")
168
+ end.compact.join("&")
164
169
  end
165
170
 
166
171
  def truncate(text, truncate_after_chars = 2000)
@@ -169,15 +174,31 @@ module Sidekiq
169
174
 
170
175
  def display_args(args, truncate_after_chars = 2000)
171
176
  args.map do |arg|
172
- a = arg.inspect
173
- h(truncate(a))
177
+ h(truncate(to_display(arg)))
174
178
  end.join(", ")
175
179
  end
176
180
 
181
+ def csrf_tag
182
+ "<input type='hidden' name='authenticity_token' value='#{session[:csrf]}'/>"
183
+ end
184
+
185
+ def to_display(arg)
186
+ begin
187
+ arg.inspect
188
+ rescue
189
+ begin
190
+ arg.to_s
191
+ rescue => ex
192
+ "Cannot display argument: [#{ex.class.name}] #{ex.message}"
193
+ end
194
+ end
195
+ end
196
+
177
197
  RETRY_JOB_KEYS = Set.new(%w(
178
198
  queue class args retry_count retried_at failed_at
179
199
  jid error_message error_class backtrace
180
200
  error_backtrace enqueued_at retry wrapped
201
+ created_at
181
202
  ))
182
203
 
183
204
  def retry_extra_items(retry_job)
@@ -230,5 +251,12 @@ module Sidekiq
230
251
  def product_version
231
252
  "Sidekiq v#{Sidekiq::VERSION}"
232
253
  end
254
+
255
+ def redis_connection_and_namespace
256
+ @redis_connection_and_namespace ||= begin
257
+ namespace_suffix = namespace == nil ? '' : "##{namespace}"
258
+ "#{redis_connection}#{namespace_suffix}"
259
+ end
260
+ end
233
261
  end
234
262
  end
@@ -24,6 +24,8 @@ module Sidekiq
24
24
  attr_accessor :jid
25
25
 
26
26
  def self.included(base)
27
+ raise ArgumentError, "You cannot include Sidekiq::Worker in an ActiveJob: #{base.name}" if base.ancestors.any? {|c| c.name == 'ActiveJob::Base' }
28
+
27
29
  base.extend(ClassMethods)
28
30
  base.class_attribute :sidekiq_options_hash
29
31
  base.class_attribute :sidekiq_retry_in_block
@@ -36,10 +38,24 @@ module Sidekiq
36
38
 
37
39
  module ClassMethods
38
40
 
41
+ def delay(*args)
42
+ raise ArgumentError, "Do not call .delay on a Sidekiq::Worker class, call .perform_async"
43
+ end
44
+
45
+ def delay_for(*args)
46
+ raise ArgumentError, "Do not call .delay_for on a Sidekiq::Worker class, call .perform_in"
47
+ end
48
+
49
+ def delay_until(*args)
50
+ raise ArgumentError, "Do not call .delay_until on a Sidekiq::Worker class, call .perform_at"
51
+ end
52
+
39
53
  def perform_async(*args)
40
54
  client_push('class' => self, 'args' => args)
41
55
  end
42
56
 
57
+ # +interval+ must be a timestamp, numeric or something that acts
58
+ # numeric (like an activesupport time interval).
43
59
  def perform_in(interval, *args)
44
60
  int = interval.to_f
45
61
  now = Time.now
data/lib/sidekiq.rb CHANGED
@@ -76,9 +76,19 @@ module Sidekiq
76
76
  defined?(Sidekiq::CLI)
77
77
  end
78
78
 
79
- def self.redis(&block)
80
- raise ArgumentError, "requires a block" unless block
81
- redis_pool.with(&block)
79
+ def self.redis
80
+ raise ArgumentError, "requires a block" unless block_given?
81
+ redis_pool.with do |conn|
82
+ retryable = true
83
+ begin
84
+ yield conn
85
+ rescue Redis::CommandError => ex
86
+ #2550 Failover can cause the server to become a slave, need
87
+ # to disconnect and reopen the socket to get back to the master.
88
+ (conn.disconnect!; retryable = false; retry) if retryable && ex.message =~ /READONLY/
89
+ raise
90
+ end
91
+ end
82
92
  end
83
93
 
84
94
  def self.redis_pool
@@ -100,11 +110,25 @@ module Sidekiq
100
110
  end
101
111
 
102
112
  def self.server_middleware
103
- @server_chain ||= Processor.default_middleware
113
+ @server_chain ||= default_server_middleware
104
114
  yield @server_chain if block_given?
105
115
  @server_chain
106
116
  end
107
117
 
118
+ def self.default_server_middleware
119
+ require 'sidekiq/middleware/server/retry_jobs'
120
+ require 'sidekiq/middleware/server/logging'
121
+
122
+ Middleware::Chain.new do |m|
123
+ m.add Middleware::Server::Logging
124
+ m.add Middleware::Server::RetryJobs
125
+ if defined?(::ActiveRecord::Base)
126
+ require 'sidekiq/middleware/server/active_record'
127
+ m.add Sidekiq::Middleware::Server::ActiveRecord
128
+ end
129
+ end
130
+ end
131
+
108
132
  def self.default_worker_options=(hash)
109
133
  @default_worker_options = default_worker_options.merge(hash.stringify_keys)
110
134
  end
@@ -129,16 +153,6 @@ module Sidekiq
129
153
  Sidekiq::Logging.logger = log
130
154
  end
131
155
 
132
- # When set, overrides Sidekiq.options[:average_scheduled_poll_interval] and sets
133
- # the average interval that this process will delay before checking for
134
- # scheduled jobs or job retries that are ready to run.
135
- #
136
- # See sidekiq/scheduled.rb for an in-depth explanation of this value
137
- def self.poll_interval=(interval)
138
- $stderr.puts "DEPRECATION: `config.poll_interval = #{interval}` will be removed in Sidekiq 4. Please update to `config.average_scheduled_poll_interval = #{interval}`."
139
- self.options[:poll_interval_average] = interval
140
- end
141
-
142
156
  # How frequently Redis should be checked by a random Sidekiq process for
143
157
  # scheduled and retriable jobs. Each individual process will take turns by
144
158
  # waiting some multiple of this value.
@@ -172,6 +186,15 @@ module Sidekiq
172
186
  raise ArgumentError, "Invalid event name: #{event}" unless options[:lifecycle_events].key?(event)
173
187
  options[:lifecycle_events][event] << block
174
188
  end
189
+
190
+ # We are shutting down Sidekiq but what about workers that
191
+ # are working on some long job? This error is
192
+ # raised in workers that have not finished within the hard
193
+ # timeout limit. This is needed to rollback db transactions,
194
+ # otherwise Ruby's Thread#kill will commit. See #377.
195
+ # DO NOT RESCUE THIS ERROR IN YOUR WORKERS
196
+ class Shutdown < Interrupt; end
197
+
175
198
  end
176
199
 
177
200
  require 'sidekiq/extensions/class_methods'
data/sidekiq.gemspec CHANGED
@@ -4,7 +4,8 @@ require File.expand_path('../lib/sidekiq/version', __FILE__)
4
4
  Gem::Specification.new do |gem|
5
5
  gem.authors = ["Mike Perham"]
6
6
  gem.email = ["mperham@gmail.com"]
7
- gem.description = gem.summary = "Simple, efficient background processing for Ruby"
7
+ gem.summary = "Simple, efficient background processing for Ruby"
8
+ gem.description = "Simple, efficient background processing for Ruby."
8
9
  gem.homepage = "http://sidekiq.org"
9
10
  gem.license = "LGPL-3.0"
10
11
 
@@ -14,14 +15,12 @@ Gem::Specification.new do |gem|
14
15
  gem.name = "sidekiq"
15
16
  gem.require_paths = ["lib"]
16
17
  gem.version = Sidekiq::VERSION
17
- gem.add_dependency 'redis', '>= 3.0.6'
18
- gem.add_dependency 'redis-namespace', '>= 1.3.1'
19
- gem.add_dependency 'connection_pool', '>= 2.1.1'
20
- gem.add_dependency 'celluloid', '~> 0.16.0'
21
- gem.add_dependency 'json'
22
- gem.add_development_dependency 'sinatra'
23
- gem.add_development_dependency 'minitest', '~> 5.3.3'
24
- gem.add_development_dependency 'rake'
25
- gem.add_development_dependency 'rails', '~> 4.1.1'
26
- gem.add_development_dependency 'coveralls'
18
+ gem.add_dependency 'redis', '~> 3.2', '>= 3.2.1'
19
+ gem.add_dependency 'connection_pool', '~> 2.2', '>= 2.2.0'
20
+ gem.add_dependency 'concurrent-ruby', '~> 1.0'
21
+ gem.add_development_dependency 'redis-namespace', '~> 1.5', '>= 1.5.2'
22
+ gem.add_development_dependency 'sinatra', '~> 1.4', '>= 1.4.6'
23
+ gem.add_development_dependency 'minitest', '~> 5.7', '>= 5.7.0'
24
+ gem.add_development_dependency 'rake', '~> 10.0'
25
+ gem.add_development_dependency 'rails', '~> 4', '>= 3.2.0'
27
26
  end
data/test/helper.rb CHANGED
@@ -1,18 +1,32 @@
1
1
  $TESTING = true
2
- require 'coveralls'
3
- Coveralls.wear! do
4
- add_filter "/test/"
5
- add_filter "/myapp/"
6
- end
2
+ # disable minitest/parallel threads
3
+ ENV["N"] = "0"
7
4
 
8
- ENV['RACK_ENV'] = ENV['RAILS_ENV'] = 'test'
9
- if ENV.has_key?("SIMPLECOV")
5
+ if ENV["COVERAGE"]
10
6
  require 'simplecov'
11
7
  SimpleCov.start do
12
8
  add_filter "/test/"
13
9
  add_filter "/myapp/"
14
10
  end
15
11
  end
12
+ ENV['RACK_ENV'] = ENV['RAILS_ENV'] = 'test'
13
+
14
+ trap 'USR1' do
15
+ threads = Thread.list
16
+
17
+ puts
18
+ puts "=" * 80
19
+ puts "Received USR1 signal; printing all #{threads.count} thread backtraces."
20
+
21
+ threads.each do |thr|
22
+ description = thr == Thread.main ? "Main thread" : thr.inspect
23
+ puts
24
+ puts "#{description} backtrace: "
25
+ puts thr.backtrace.join("\n")
26
+ end
27
+
28
+ puts "=" * 80
29
+ end
16
30
 
17
31
  begin
18
32
  require 'pry-byebug'
@@ -20,10 +34,7 @@ rescue LoadError
20
34
  end
21
35
 
22
36
  require 'minitest/autorun'
23
- require 'minitest/pride'
24
37
 
25
- require 'celluloid/test'
26
- Celluloid.boot
27
38
  require 'sidekiq'
28
39
  require 'sidekiq/util'
29
40
  Sidekiq.logger.level = Logger::ERROR
@@ -37,3 +48,27 @@ REDIS = Sidekiq::RedisConnection.create(:url => REDIS_URL, :namespace => 'testy'
37
48
  Sidekiq.configure_client do |config|
38
49
  config.redis = { :url => REDIS_URL, :namespace => 'testy' }
39
50
  end
51
+
52
+ def capture_logging(lvl=Logger::INFO)
53
+ old = Sidekiq.logger
54
+ begin
55
+ out = StringIO.new
56
+ logger = Logger.new(out)
57
+ logger.level = lvl
58
+ Sidekiq.logger = logger
59
+ yield
60
+ out.string
61
+ ensure
62
+ Sidekiq.logger = old
63
+ end
64
+ end
65
+
66
+ def with_logging(lvl=Logger::DEBUG)
67
+ old = Sidekiq.logger.level
68
+ begin
69
+ Sidekiq.logger.level = lvl
70
+ yield
71
+ ensure
72
+ Sidekiq.logger.level = old
73
+ end
74
+ end