sidekiq 1.1.4 → 1.2.0

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.

@@ -26,7 +26,15 @@ You may not, without Our prior written consent, redistribute the Software or Mod
26
26
 
27
27
  UNDER NO CIRCUMSTANCES MAY YOU USE THE SOFTWARE FOR A PRODUCT THAT IS INTENDED FOR SOFTWARE OR APPLICATION DEVELOPMENT PURPOSES.
28
28
 
29
- The Open Source version of the Software (“GPL Version”) is licensed under the terms of the GNU General Public License versions 3.0 (“GPL”) and not under this License Agreement. If You, or another third party, has, at any time, developed all (or any portions of) the Application(s) using the GPL Version, You may not combine such development work with the Software and must license such Application(s) (or any portions derived there from) under the terms of the GNU General Public License version 3, a copy of which is located at http://www.gnu.org/copyleft/gpl.html.
29
+ The Open Source version of the Software (“LGPL Version”) is licensed
30
+ under the terms of the GNU Lesser General Public License versions 3.0
31
+ (“LGPL”) and not under this License Agreement. If You, or another third
32
+ party, has, at any time, developed all (or any portions of) the
33
+ Application(s) using the LGPL Version, You may not combine such
34
+ development work with the Software and must license such Application(s)
35
+ (or any portions derived there from) under the terms of the GNU Lesser
36
+ General Public License version 3, a copy of which is located at
37
+ http://www.gnu.org/copyleft/lgpl.html.
30
38
 
31
39
  5. TERMINATION
32
40
 
data/Changes.md CHANGED
@@ -1,3 +1,34 @@
1
+ 1.2.0
2
+ -----------
3
+
4
+ - Full or partial error backtraces can optionally be stored as part of the retry
5
+ for display in the web UI if you aren't using an error service. [#155]
6
+
7
+ ```ruby
8
+ class Worker
9
+ include Sidekiq::Worker
10
+ sidekiq_options :backtrace => [true || 10]
11
+ end
12
+ ```
13
+ - Add timeout option to kill a worker after N seconds (blackgold9)
14
+
15
+ ```ruby
16
+ class HangingWorker
17
+ include Sidekiq::Worker
18
+ sidekiq_options :timeout => 600
19
+ def perform
20
+ # will be killed if it takes longer than 10 minutes
21
+ end
22
+ end
23
+ ```
24
+
25
+ - Fix delayed extensions not available in workers [#152]
26
+ - In test environments add the `#drain` class method to workers. This method
27
+ executes all previously queued jobs. (panthomakos)
28
+ - Sidekiq workers can be run inline during tests, just `require 'sidekiq/testing/inline'` (panthomakos)
29
+ - Queues can now be deleted from the Sidekiq web UI [#154]
30
+ - Fix unnecessary shutdown delay due to Retry Poller [#174]
31
+
1
32
  1.1.4
2
33
  -----------
3
34
 
data/Gemfile CHANGED
@@ -4,7 +4,7 @@ gemspec
4
4
  gem 'slim'
5
5
  gem 'sprockets'
6
6
  gem 'sass'
7
- gem 'rails'
7
+ gem 'rails', '3.2.3'
8
8
  gem 'sqlite3'
9
9
 
10
10
  group :test do
@@ -12,7 +12,7 @@ class Sidekiqctl
12
12
  @timeout = timeout
13
13
 
14
14
  done 'No pidfile given' if !pidfile
15
- done 'Pidfile does not exist' if !File.exist?(pidfile)
15
+ done "Pidfile #{pidfile} does not exist" if !File.exist?(pidfile)
16
16
  done 'Invalid pidfile content' if pid == 0
17
17
 
18
18
  fetch_process
@@ -1,12 +1,12 @@
1
1
  require 'sidekiq/version'
2
2
  require 'sidekiq/client'
3
3
  require 'sidekiq/worker'
4
- require 'sidekiq/rails'
5
4
  require 'sidekiq/redis_connection'
6
5
  require 'sidekiq/util'
7
6
 
8
7
  require 'sidekiq/extensions/action_mailer'
9
8
  require 'sidekiq/extensions/active_record'
9
+ require 'sidekiq/rails' if defined?(::Rails)
10
10
 
11
11
  module Sidekiq
12
12
 
@@ -83,21 +83,11 @@ module Sidekiq
83
83
  end
84
84
 
85
85
  def self.load_json(string)
86
- # Can't reliably detect whether MultiJson responds to load, since it's
87
- # a reserved word. Use adapter as a proxy for new features.
88
- if MultiJson.respond_to?(:adapter)
89
- MultiJson.load(string)
90
- else
91
- MultiJson.decode(string)
92
- end
86
+ MultiJson.decode(string)
93
87
  end
94
88
 
95
89
  def self.dump_json(object)
96
- if MultiJson.respond_to?(:dump)
97
- MultiJson.dump(object)
98
- else
99
- MultiJson.encode(object)
100
- end
90
+ MultiJson.encode(object)
101
91
  end
102
92
 
103
93
  end
@@ -64,7 +64,7 @@ module Sidekiq
64
64
  sleep
65
65
  rescue Interrupt
66
66
  logger.info 'Shutting down'
67
- poller.terminate if poller.alive?
67
+ poller.terminate! if poller.alive?
68
68
  @manager.stop!(:shutdown => true, :timeout => options[:timeout])
69
69
  @manager.wait(:shutdown)
70
70
  # Explicitly exit so busy Processor threads can't block
@@ -93,6 +93,8 @@ module Sidekiq
93
93
  raise ArgumentError, "#{options[:require]} does not exist" unless File.exist?(options[:require])
94
94
 
95
95
  if File.directory?(options[:require])
96
+ require 'rails'
97
+ require 'sidekiq/rails'
96
98
  require File.expand_path("#{options[:require]}/config/environment.rb")
97
99
  ::Rails.application.eager_load!
98
100
  else
@@ -26,6 +26,7 @@ module Sidekiq
26
26
  # class - the worker class to call, required
27
27
  # args - an array of simple arguments to the perform method, must be JSON-serializable
28
28
  # retry - whether to retry this job if it fails, true or false, default true
29
+ # backtrace - whether to save any error backtrace, default false
29
30
  #
30
31
  # All options must be strings, not symbols. NB: because we are serializing to JSON, all
31
32
  # symbols in 'args' will be converted to strings.
@@ -38,11 +39,13 @@ module Sidekiq
38
39
  raise(ArgumentError, "Message must include a class and set of arguments: #{item.inspect}") if !item['class'] || !item['args']
39
40
  raise(ArgumentError, "Message must include a Sidekiq::Worker class, not class name: #{item['class'].ancestors.inspect}") if !item['class'].is_a?(Class) || !item['class'].respond_to?('get_sidekiq_options')
40
41
 
41
- item['retry'] = !!item['class'].get_sidekiq_options['retry']
42
- queue = item['queue'] || item['class'].get_sidekiq_options['queue'] || 'default'
43
42
  worker_class = item['class']
44
43
  item['class'] = item['class'].to_s
45
44
 
45
+ item = worker_class.get_sidekiq_options.merge(item)
46
+ item['retry'] = !!item['retry']
47
+ queue = item['queue']
48
+
46
49
  pushed = false
47
50
  Sidekiq.client_middleware.invoke(worker_class, item, queue) do
48
51
  payload = Sidekiq.dump_json(item)
@@ -63,7 +66,7 @@ module Sidekiq
63
66
  # Messages are enqueued to the 'default' queue.
64
67
  #
65
68
  def self.enqueue(klass, *args)
66
- push('class' => klass, 'args' => args)
69
+ klass.perform_async(*args)
67
70
  end
68
71
  end
69
72
  end
@@ -42,6 +42,12 @@ module Sidekiq
42
42
  msg['retry_count'] = 0
43
43
  end
44
44
 
45
+ if msg['backtrace'] == true
46
+ msg['error_backtrace'] = e.backtrace
47
+ elsif msg['backtrace'].to_i != 0
48
+ msg['error_backtrace'] = e.backtrace[0..msg['backtrace'].to_i]
49
+ end
50
+
45
51
  if count <= MAX_COUNT
46
52
  delay = DELAY.call(count)
47
53
  logger.debug { "Failure! Retry #{count} in #{delay} seconds" }
@@ -0,0 +1,21 @@
1
+ require 'timeout'
2
+
3
+ module Sidekiq
4
+ module Middleware
5
+ module Server
6
+ class Timeout
7
+
8
+ def call(worker, msg, queue)
9
+ if msg['timeout'] && msg['timeout'].to_i != 0
10
+ ::Timeout.timeout(msg['timeout'].to_i) do
11
+ yield
12
+ end
13
+ else
14
+ yield
15
+ end
16
+ end
17
+
18
+ end
19
+ end
20
+ end
21
+ end
@@ -6,6 +6,7 @@ require 'sidekiq/middleware/server/active_record'
6
6
  require 'sidekiq/middleware/server/exception_handler'
7
7
  require 'sidekiq/middleware/server/retry_jobs'
8
8
  require 'sidekiq/middleware/server/logging'
9
+ require 'sidekiq/middleware/server/timeout'
9
10
 
10
11
  module Sidekiq
11
12
  class Processor
@@ -18,6 +19,7 @@ module Sidekiq
18
19
  m.add Middleware::Server::Logging
19
20
  m.add Middleware::Server::RetryJobs
20
21
  m.add Middleware::Server::ActiveRecord
22
+ m.add Middleware::Server::Timeout
21
23
  end
22
24
  end
23
25
 
@@ -33,6 +33,12 @@ module Sidekiq
33
33
  def jobs
34
34
  @pushed ||= []
35
35
  end
36
+
37
+ def drain
38
+ while job = jobs.shift do
39
+ new.perform(*job['args'])
40
+ end
41
+ end
36
42
  end
37
43
  end
38
44
  end
@@ -0,0 +1,37 @@
1
+ module Sidekiq
2
+ module Worker
3
+
4
+ ##
5
+ # The Sidekiq inline infrastructure overrides the perform_async so that it
6
+ # actually calls perform instead. This allows workers to be run inline in a
7
+ # testing environment.
8
+ #
9
+ # This is similar to `Resque.inline = true` functionality.
10
+ #
11
+ # Example:
12
+ #
13
+ # require 'sidekiq/testing/inline'
14
+ #
15
+ # $external_variable = 0
16
+ #
17
+ # class ExternalWorker
18
+ # include Sidekiq::Worker
19
+ #
20
+ # def perform
21
+ # $external_variable = 1
22
+ # end
23
+ # end
24
+ #
25
+ # assert_equal 0, $external_variable
26
+ # ExternalWorker.perform_async
27
+ # assert_equal 1, $external_variable
28
+ #
29
+ module ClassMethods
30
+ alias_method :perform_async_old, :perform_async
31
+ def perform_async(*args)
32
+ new.perform(*args)
33
+ true
34
+ end
35
+ end
36
+ end
37
+ end
@@ -1,3 +1,3 @@
1
1
  module Sidekiq
2
- VERSION = "1.1.4"
2
+ VERSION = "1.2.0"
3
3
  end
@@ -21,7 +21,7 @@ module Sidekiq
21
21
  def call(env)
22
22
  # Solve the problem of people requesting /sidekiq when they need to request /sidekiq/ so
23
23
  # that relative links in templates resolve correctly.
24
- return [301, { 'Location' => "#{env['SCRIPT_NAME']}/" }, ['redirecting']] if env['SCRIPT_NAME'] == env['REQUEST_PATH']
24
+ return [301, { 'Location' => "#{env['SCRIPT_NAME']}/", 'Content-Type' => 'text/html' }, ['redirecting']] if env['SCRIPT_NAME'] == env['REQUEST_PATH']
25
25
 
26
26
  return @app.call(env) unless @matcher =~ env["PATH_INFO"]
27
27
  env['PATH_INFO'].sub!(@matcher,'')
@@ -38,15 +38,6 @@ module Sidekiq
38
38
 
39
39
  helpers do
40
40
 
41
- def reset_worker_list
42
- Sidekiq.redis do |conn|
43
- workers = conn.smembers('workers')
44
- workers.each do |name|
45
- conn.srem('workers', name)
46
- end
47
- end
48
- end
49
-
50
41
  def workers
51
42
  @workers ||= begin
52
43
  Sidekiq.redis do |conn|
@@ -114,21 +105,27 @@ module Sidekiq
114
105
  slim :index
115
106
  end
116
107
 
117
- post "/reset" do
118
- reset_worker_list
119
- redirect root_path
120
- end
121
-
122
108
  get "/queues/:name" do
123
109
  halt 404 unless params[:name]
110
+ count = (params[:count] || 10).to_i
124
111
  @name = params[:name]
125
- @messages = Sidekiq.redis {|conn| conn.lrange("queue:#{@name}", 0, 10) }.map { |str| Sidekiq.load_json(str) }
112
+ @messages = Sidekiq.redis {|conn| conn.lrange("queue:#{@name}", 0, count) }.map { |str| Sidekiq.load_json(str) }
126
113
  slim :queue
127
114
  end
128
115
 
116
+ post "/queues/:name" do
117
+ Sidekiq.redis do |conn|
118
+ conn.del("queue:#{params[:name]}")
119
+ conn.srem("queues", params[:name])
120
+ end
121
+ redirect root_path
122
+ end
123
+
129
124
  get "/retries/:score" do
130
125
  halt 404 unless params[:score]
131
126
  @score = params[:score].to_f
127
+ @retries = retries_with_score(@score)
128
+ redirect root_path if @retries.empty?
132
129
  slim :retry
133
130
  end
134
131
 
@@ -36,6 +36,9 @@ module Sidekiq
36
36
  # :unique - enable the UniqueJobs middleware for this Worker, default *true*
37
37
  # :queue - use a named queue for this Worker, default 'default'
38
38
  # :retry - enable the RetryJobs middleware for this Worker, default *true*
39
+ # :timeout - timeout the perform method after N seconds, default *nil*
40
+ # :backtrace - whether to save any error backtrace in the retry payload to display in web UI,
41
+ # can be true, false or an integer number of lines to save, default *false*
39
42
  def sidekiq_options(opts={})
40
43
  @sidekiq_options = get_sidekiq_options.merge(stringify_keys(opts || {}))
41
44
  end
@@ -0,0 +1,21 @@
1
+ # YAML marshalling of instances can fail in some circumstances,
2
+ # e.g. when the instance has a handle to a Proc. This monkeypatch limits
3
+ # the YAML serialization to just AR's internal @attributes hash.
4
+ # The paperclip gem litters AR instances with Procs, for instance.
5
+ #
6
+ # Courtesy of @ryanlecompte https://gist.github.com/007b88ae90372d1a3321
7
+ #
8
+
9
+ if defined?(::ActiveRecord)
10
+ class ActiveRecord::Base
11
+ yaml_as "tag:ruby.yaml.org,2002:ActiveRecord"
12
+
13
+ def self.yaml_new(klass, tag, val)
14
+ klass.unscoped.find(val['attributes'][klass.primary_key])
15
+ end
16
+
17
+ def to_yaml_properties
18
+ ['@attributes']
19
+ end
20
+ end
21
+ end
@@ -1,5 +1,6 @@
1
1
  class HardWorker
2
2
  include Sidekiq::Worker
3
+ sidekiq_options :timeout => 60, :backtrace => 5, :timeout => 20
3
4
 
4
5
  def perform(name, count, salt)
5
6
  raise name if name == 'crash'
@@ -17,7 +17,7 @@ Gem::Specification.new do |gem|
17
17
  gem.add_dependency 'redis-namespace'
18
18
  gem.add_dependency 'connection_pool', '~> 0.9.0'
19
19
  gem.add_dependency 'celluloid', '~> 0.10.0'
20
- gem.add_dependency 'multi_json', '~> 1.0'
20
+ gem.add_dependency 'multi_json', '~> 1'
21
21
  gem.add_development_dependency 'minitest'
22
22
  gem.add_development_dependency 'sinatra'
23
23
  gem.add_development_dependency 'slim'
@@ -1,3 +1,4 @@
1
+ ENV['RACK_ENV'] = ENV['RAILS_ENV'] = 'test'
1
2
  if ENV.has_key?("SIMPLECOV")
2
3
  require 'simplecov'
3
4
  SimpleCov.start
@@ -96,8 +96,7 @@ class TestClient < MiniTest::Unit::TestCase
96
96
 
97
97
  class QueuedWorker
98
98
  include Sidekiq::Worker
99
-
100
- sidekiq_options :queue => :flimflam
99
+ sidekiq_options :queue => :flimflam, :timeout => 1
101
100
  end
102
101
 
103
102
  it 'enqueues to the named queue' do
@@ -4,6 +4,7 @@ require 'active_record'
4
4
  require 'action_mailer'
5
5
  require 'sidekiq/extensions/action_mailer'
6
6
  require 'sidekiq/extensions/active_record'
7
+ require 'sidekiq/rails'
7
8
 
8
9
  Sidekiq.hook_rails!
9
10
 
@@ -20,7 +21,7 @@ class TestExtensions < MiniTest::Unit::TestCase
20
21
  end
21
22
  end
22
23
 
23
- it 'allows delayed exection of ActiveRecord class methods' do
24
+ it 'allows delayed execution of ActiveRecord class methods' do
24
25
  assert_equal [], Sidekiq::Client.registered_queues
25
26
  assert_equal 0, Sidekiq.redis {|c| c.llen('queue:default') }
26
27
  MyModel.delay.long_class_method
@@ -16,6 +16,7 @@ class TestManager < MiniTest::Unit::TestCase
16
16
 
17
17
  class IntegrationWorker
18
18
  include Sidekiq::Worker
19
+ sidekiq_options :queue => 'foo'
19
20
 
20
21
  def perform(a, b)
21
22
  $mutex.synchronize do
@@ -26,8 +27,8 @@ class TestManager < MiniTest::Unit::TestCase
26
27
  end
27
28
 
28
29
  it 'processes messages' do
29
- Sidekiq::Client.push('queue' => :foo, 'class' => IntegrationWorker, 'args' => [1, 2])
30
- Sidekiq::Client.push('queue' => :foo, 'class' => IntegrationWorker, 'args' => [1, 3])
30
+ IntegrationWorker.perform_async(1, 2)
31
+ IntegrationWorker.perform_async(1, 3)
31
32
 
32
33
  q = TimedQueue.new
33
34
  mgr = Sidekiq::Manager.new(:queues => [:foo], :concurrency => 2)
@@ -25,6 +25,34 @@ class TestRetry < MiniTest::Unit::TestCase
25
25
  assert_equal msg, msg2
26
26
  end
27
27
 
28
+ it 'saves backtraces' do
29
+ @redis.expect :zadd, 1, ['retry', String, String]
30
+ msg = { 'class' => 'Bob', 'args' => [1,2,'foo'], 'retry' => true, 'backtrace' => true }
31
+ handler = Sidekiq::Middleware::Server::RetryJobs.new
32
+ c = nil
33
+ assert_raises RuntimeError do
34
+ handler.call('', msg, 'default') do
35
+ c = caller(0); raise "kerblammo!"
36
+ end
37
+ end
38
+ assert msg["error_backtrace"]
39
+ assert_equal c, msg["error_backtrace"]
40
+ end
41
+
42
+ it 'saves partial backtraces' do
43
+ @redis.expect :zadd, 1, ['retry', String, String]
44
+ msg = { 'class' => 'Bob', 'args' => [1,2,'foo'], 'retry' => true, 'backtrace' => 3 }
45
+ handler = Sidekiq::Middleware::Server::RetryJobs.new
46
+ c = nil
47
+ assert_raises RuntimeError do
48
+ handler.call('', msg, 'default') do
49
+ c = caller(0)[0..3]; raise "kerblammo!"
50
+ end
51
+ end
52
+ assert msg["error_backtrace"]
53
+ assert_equal c, msg["error_backtrace"]
54
+ end
55
+
28
56
  it 'handles a new failed message' do
29
57
  @redis.expect :zadd, 1, ['retry', String, String]
30
58
  msg = { 'class' => 'Bob', 'args' => [1,2,'foo'], 'retry' => true }
@@ -38,6 +66,7 @@ class TestRetry < MiniTest::Unit::TestCase
38
66
  assert_equal 'kerblammo!', msg["error_message"]
39
67
  assert_equal 'RuntimeError', msg["error_class"]
40
68
  assert_equal 0, msg["retry_count"]
69
+ refute msg["error_backtrace"]
41
70
  assert msg["failed_at"]
42
71
  @redis.verify
43
72
  end
@@ -3,6 +3,7 @@ require 'sidekiq'
3
3
  require 'sidekiq/worker'
4
4
  require 'active_record'
5
5
  require 'action_mailer'
6
+ require 'sidekiq/rails'
6
7
  require 'sidekiq/extensions/action_mailer'
7
8
  require 'sidekiq/extensions/active_record'
8
9
 
@@ -10,6 +11,7 @@ Sidekiq.hook_rails!
10
11
 
11
12
  class TestTesting < MiniTest::Unit::TestCase
12
13
  describe 'sidekiq testing' do
14
+ class PerformError < RuntimeError; end
13
15
 
14
16
  class DirectWorker
15
17
  include Sidekiq::Worker
@@ -18,6 +20,20 @@ class TestTesting < MiniTest::Unit::TestCase
18
20
  end
19
21
  end
20
22
 
23
+ class EnqueuedWorker
24
+ include Sidekiq::Worker
25
+ def perform(a, b)
26
+ a + b
27
+ end
28
+ end
29
+
30
+ class StoredWorker
31
+ include Sidekiq::Worker
32
+ def perform(error)
33
+ raise PerformError if error
34
+ end
35
+ end
36
+
21
37
  class FooMailer < ActionMailer::Base
22
38
  def bar(str)
23
39
  str
@@ -31,7 +47,7 @@ class TestTesting < MiniTest::Unit::TestCase
31
47
  end
32
48
 
33
49
  before do
34
- require 'sidekiq/testing'
50
+ load 'sidekiq/testing.rb'
35
51
  end
36
52
 
37
53
  after do
@@ -43,23 +59,39 @@ class TestTesting < MiniTest::Unit::TestCase
43
59
  end
44
60
  end
45
61
 
46
- it 'stubs the async call when in testing mode' do
47
- # We can only have one it block here so all 'testing' tests
48
- # have to go here because require 'sidekiq/testing' changes
49
- # how Sidekiq works and we need to roll back those changes
50
- # when the test is done.
62
+ it 'stubs the async call' do
51
63
  assert_equal 0, DirectWorker.jobs.size
52
64
  assert DirectWorker.perform_async(1, 2)
53
65
  assert_equal 1, DirectWorker.jobs.size
66
+ end
54
67
 
68
+ it 'stubs the delay call on mailers' do
55
69
  assert_equal 0, Sidekiq::Extensions::DelayedMailer.jobs.size
56
70
  FooMailer.delay.bar('hello!')
57
71
  assert_equal 1, Sidekiq::Extensions::DelayedMailer.jobs.size
72
+ end
58
73
 
74
+ it 'stubs the delay call on models' do
59
75
  assert_equal 0, Sidekiq::Extensions::DelayedModel.jobs.size
60
76
  FooModel.delay.bar('hello!')
61
77
  assert_equal 1, Sidekiq::Extensions::DelayedModel.jobs.size
62
78
  end
63
79
 
80
+ it 'stubs the enqueue call' do
81
+ assert_equal 0, EnqueuedWorker.jobs.size
82
+ assert Sidekiq::Client.enqueue(EnqueuedWorker, 1, 2)
83
+ assert_equal 1, EnqueuedWorker.jobs.size
84
+ end
85
+
86
+ it 'executes all stored jobs' do
87
+ assert StoredWorker.perform_async(false)
88
+ assert StoredWorker.perform_async(true)
89
+
90
+ assert_equal 2, StoredWorker.jobs.size
91
+ assert_raises PerformError do
92
+ StoredWorker.drain
93
+ end
94
+ assert_equal 0, StoredWorker.jobs.size
95
+ end
64
96
  end
65
97
  end
@@ -0,0 +1,75 @@
1
+ require 'helper'
2
+ require 'sidekiq'
3
+ require 'sidekiq/worker'
4
+ require 'active_record'
5
+ require 'action_mailer'
6
+ require 'sidekiq/rails'
7
+ require 'sidekiq/extensions/action_mailer'
8
+ require 'sidekiq/extensions/active_record'
9
+
10
+ Sidekiq.hook_rails!
11
+
12
+ class TestInline < MiniTest::Unit::TestCase
13
+ describe 'sidekiq inline testing' do
14
+ class InlineError < RuntimeError; end
15
+
16
+ class InlineWorker
17
+ include Sidekiq::Worker
18
+ def perform(pass)
19
+ raise InlineError unless pass
20
+ end
21
+ end
22
+
23
+ class InlineFooMailer < ActionMailer::Base
24
+ def bar(str)
25
+ raise InlineError
26
+ end
27
+ end
28
+
29
+ class InlineFooModel < ActiveRecord::Base
30
+ def self.bar(str)
31
+ raise InlineError
32
+ end
33
+ end
34
+
35
+ before do
36
+ load 'sidekiq/testing/inline.rb'
37
+ end
38
+
39
+ after do
40
+ Sidekiq::Worker::ClassMethods.class_eval do
41
+ remove_method :perform_async
42
+ alias_method :perform_async, :perform_async_old
43
+ remove_method :perform_async_old
44
+ end
45
+ end
46
+
47
+ it 'stubs the async call when in testing mode' do
48
+ assert InlineWorker.perform_async(true)
49
+
50
+ assert_raises InlineError do
51
+ InlineWorker.perform_async(false)
52
+ end
53
+ end
54
+
55
+ it 'stubs the delay call on mailers' do
56
+ assert_raises InlineError do
57
+ InlineFooMailer.delay.bar('three')
58
+ end
59
+ end
60
+
61
+ it 'stubs the delay call on models' do
62
+ assert_raises InlineError do
63
+ InlineFooModel.delay.bar('three')
64
+ end
65
+ end
66
+
67
+ it 'stubs the enqueue call when in testing mode' do
68
+ assert Sidekiq::Client.enqueue(InlineWorker, true)
69
+
70
+ assert_raises InlineError do
71
+ Sidekiq::Client.enqueue(InlineWorker, false)
72
+ end
73
+ end
74
+ end
75
+ end
@@ -52,10 +52,31 @@ class TestWeb < MiniTest::Unit::TestCase
52
52
  assert_equal 404, last_response.status
53
53
  end
54
54
 
55
+ it 'handles missing retry' do
56
+ get '/retries/12391982.123'
57
+ assert_equal 302, last_response.status
58
+ end
59
+
55
60
  it 'handles queue view' do
56
61
  get '/queues/default'
57
62
  assert_equal 200, last_response.status
58
63
  end
59
64
 
65
+ it 'can delete a queue' do
66
+ Sidekiq.redis do |conn|
67
+ conn.rpush('queue:foo', '{}')
68
+ conn.sadd('queues', 'foo')
69
+ end
70
+
71
+ get '/queues/foo'
72
+ assert_equal 200, last_response.status
73
+
74
+ post '/queues/foo'
75
+ assert_equal 302, last_response.status
76
+
77
+ Sidekiq.redis do |conn|
78
+ refute conn.smembers('queues').include?('foo')
79
+ end
80
+ end
60
81
  end
61
82
  end
@@ -1,11 +1,23 @@
1
1
  /*
2
- *= require_self
3
2
  *= require vendor/bootstrap
4
3
  *= require vendor/bootstrap-responsive
4
+ *= require_self
5
5
  */
6
6
  body {
7
7
  position: relative;
8
8
  padding-top: 90px;
9
- background-color: #aaa;
10
9
  }
11
10
 
11
+ td form {
12
+ margin: 0;
13
+ }
14
+
15
+ td form .btn {
16
+ margin: 0;
17
+ }
18
+
19
+ code {
20
+ padding: 0;
21
+ border: 0;
22
+ background-color: inherit;
23
+ }
@@ -30,19 +30,21 @@
30
30
  td= msg['payload']['class']
31
31
  td= msg['payload']['args'].inspect[0..100]
32
32
  td== relative_time(Time.parse(msg['run_at']))
33
- form action="#{root_path}reset" method="post"
34
- button.btn type="submit" Clear worker list
35
33
 
36
34
  #queues.tab-pane
37
35
  table class="table table-striped table-bordered"
38
36
  tr
39
37
  th Queue
40
38
  th Size
39
+ th
41
40
  - queues.each do |(queue, size)|
42
41
  tr
43
42
  td
44
- a href="queues/#{queue}" #{queue}
43
+ a href="#{root_path}queues/#{queue}" #{queue}
45
44
  td= size
45
+ td
46
+ form action="#{root_path}queues/#{queue}" method="post"
47
+ input.btn.btn-danger type="submit" name="delete" value="Delete"
46
48
 
47
49
  #retries.tab-pane
48
50
  table class="table table-striped table-bordered"
@@ -1,7 +1,7 @@
1
1
  header
2
- h1 Retry Job
2
+ h1 Job
3
3
 
4
- - retries_with_score(@score).each do |msg|
4
+ - @retries.each do |msg|
5
5
  table class="table table-striped table-bordered"
6
6
  tbody
7
7
  tr
@@ -16,13 +16,6 @@ header
16
16
  th Job Arguments
17
17
  td
18
18
  code= msg['args'].inspect[0..1000]
19
- tr
20
- th Error Class
21
- td
22
- code= msg['error_class']
23
- tr
24
- th Error Message
25
- td= msg['error_message']
26
19
  - if msg['retry_count'] > 0
27
20
  tr
28
21
  th Retry Count
@@ -38,6 +31,21 @@ header
38
31
  th Next Retry
39
32
  td== relative_time(Time.at(@score))
40
33
 
34
+ h1 Error
35
+ table class="table table-striped table-bordered"
36
+ tbody
37
+ tr
38
+ th Error Class
39
+ td
40
+ code= msg['error_class']
41
+ tr
42
+ th Error Message
43
+ td= msg['error_message']
44
+ - if !msg['error_backtrace'].nil?
45
+ tr
46
+ th Error Backtrace
47
+ td
48
+ code== msg['error_backtrace'].join("<br/>")
41
49
  form.form-horizontal action="#{root_path}retries/#{@score}" method="post"
42
50
  a.btn href="#{root_path}" &larr; Back
43
51
  input.btn.btn-primary type="submit" name="retry" value="Retry Now"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sidekiq
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.4
4
+ version: 1.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-04-25 00:00:00.000000000 Z
12
+ date: 2012-05-07 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: redis
16
- requirement: &70161328001220 !ruby/object:Gem::Requirement
16
+ requirement: &70181602671160 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70161328001220
24
+ version_requirements: *70181602671160
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: redis-namespace
27
- requirement: &70161328000340 !ruby/object:Gem::Requirement
27
+ requirement: &70181602670700 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '0'
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *70161328000340
35
+ version_requirements: *70181602670700
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: connection_pool
38
- requirement: &70161327999200 !ruby/object:Gem::Requirement
38
+ requirement: &70181602669980 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ~>
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: 0.9.0
44
44
  type: :runtime
45
45
  prerelease: false
46
- version_requirements: *70161327999200
46
+ version_requirements: *70181602669980
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: celluloid
49
- requirement: &70161327998620 !ruby/object:Gem::Requirement
49
+ requirement: &70181602669040 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ~>
@@ -54,21 +54,21 @@ dependencies:
54
54
  version: 0.10.0
55
55
  type: :runtime
56
56
  prerelease: false
57
- version_requirements: *70161327998620
57
+ version_requirements: *70181602669040
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: multi_json
60
- requirement: &70161327997960 !ruby/object:Gem::Requirement
60
+ requirement: &70181602668580 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ~>
64
64
  - !ruby/object:Gem::Version
65
- version: '1.0'
65
+ version: '1'
66
66
  type: :runtime
67
67
  prerelease: false
68
- version_requirements: *70161327997960
68
+ version_requirements: *70181602668580
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: minitest
71
- requirement: &70161327996900 !ruby/object:Gem::Requirement
71
+ requirement: &70181602684540 !ruby/object:Gem::Requirement
72
72
  none: false
73
73
  requirements:
74
74
  - - ! '>='
@@ -76,10 +76,10 @@ dependencies:
76
76
  version: '0'
77
77
  type: :development
78
78
  prerelease: false
79
- version_requirements: *70161327996900
79
+ version_requirements: *70181602684540
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: sinatra
82
- requirement: &70161327996420 !ruby/object:Gem::Requirement
82
+ requirement: &70181602683860 !ruby/object:Gem::Requirement
83
83
  none: false
84
84
  requirements:
85
85
  - - ! '>='
@@ -87,10 +87,10 @@ dependencies:
87
87
  version: '0'
88
88
  type: :development
89
89
  prerelease: false
90
- version_requirements: *70161327996420
90
+ version_requirements: *70181602683860
91
91
  - !ruby/object:Gem::Dependency
92
92
  name: slim
93
- requirement: &70161328012260 !ruby/object:Gem::Requirement
93
+ requirement: &70181602683240 !ruby/object:Gem::Requirement
94
94
  none: false
95
95
  requirements:
96
96
  - - ! '>='
@@ -98,10 +98,10 @@ dependencies:
98
98
  version: '0'
99
99
  type: :development
100
100
  prerelease: false
101
- version_requirements: *70161328012260
101
+ version_requirements: *70181602683240
102
102
  - !ruby/object:Gem::Dependency
103
103
  name: rake
104
- requirement: &70161328011740 !ruby/object:Gem::Requirement
104
+ requirement: &70181602682820 !ruby/object:Gem::Requirement
105
105
  none: false
106
106
  requirements:
107
107
  - - ! '>='
@@ -109,10 +109,10 @@ dependencies:
109
109
  version: '0'
110
110
  type: :development
111
111
  prerelease: false
112
- version_requirements: *70161328011740
112
+ version_requirements: *70181602682820
113
113
  - !ruby/object:Gem::Dependency
114
114
  name: actionmailer
115
- requirement: &70161328011180 !ruby/object:Gem::Requirement
115
+ requirement: &70181602682300 !ruby/object:Gem::Requirement
116
116
  none: false
117
117
  requirements:
118
118
  - - ~>
@@ -120,10 +120,10 @@ dependencies:
120
120
  version: '3'
121
121
  type: :development
122
122
  prerelease: false
123
- version_requirements: *70161328011180
123
+ version_requirements: *70181602682300
124
124
  - !ruby/object:Gem::Dependency
125
125
  name: activerecord
126
- requirement: &70161328010660 !ruby/object:Gem::Requirement
126
+ requirement: &70181602681760 !ruby/object:Gem::Requirement
127
127
  none: false
128
128
  requirements:
129
129
  - - ~>
@@ -131,7 +131,7 @@ dependencies:
131
131
  version: '3'
132
132
  type: :development
133
133
  prerelease: false
134
- version_requirements: *70161328010660
134
+ version_requirements: *70181602681760
135
135
  description: Simple, efficient message processing for Ruby
136
136
  email:
137
137
  - mperham@gmail.com
@@ -181,16 +181,19 @@ files:
181
181
  - lib/sidekiq/middleware/server/failure_jobs.rb
182
182
  - lib/sidekiq/middleware/server/logging.rb
183
183
  - lib/sidekiq/middleware/server/retry_jobs.rb
184
+ - lib/sidekiq/middleware/server/timeout.rb
184
185
  - lib/sidekiq/middleware/server/unique_jobs.rb
185
186
  - lib/sidekiq/processor.rb
186
187
  - lib/sidekiq/rails.rb
187
188
  - lib/sidekiq/redis_connection.rb
188
189
  - lib/sidekiq/retry.rb
189
190
  - lib/sidekiq/testing.rb
191
+ - lib/sidekiq/testing/inline.rb
190
192
  - lib/sidekiq/util.rb
191
193
  - lib/sidekiq/version.rb
192
194
  - lib/sidekiq/web.rb
193
195
  - lib/sidekiq/worker.rb
196
+ - lib/sidekiq/yaml_patch.rb
194
197
  - myapp/.gitignore
195
198
  - myapp/Capfile
196
199
  - myapp/Gemfile
@@ -243,6 +246,7 @@ files:
243
246
  - test/test_retry.rb
244
247
  - test/test_stats.rb
245
248
  - test/test_testing.rb
249
+ - test/test_testing_inline.rb
246
250
  - test/test_web.rb
247
251
  - web/assets/images/bootstrap/glyphicons-halflings-white.png
248
252
  - web/assets/images/bootstrap/glyphicons-halflings.png
@@ -306,4 +310,5 @@ test_files:
306
310
  - test/test_retry.rb
307
311
  - test/test_stats.rb
308
312
  - test/test_testing.rb
313
+ - test/test_testing_inline.rb
309
314
  - test/test_web.rb