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.
- data/COMM-LICENSE +9 -1
- data/Changes.md +31 -0
- data/Gemfile +1 -1
- data/bin/sidekiqctl +1 -1
- data/lib/sidekiq.rb +3 -13
- data/lib/sidekiq/cli.rb +3 -1
- data/lib/sidekiq/client.rb +6 -3
- data/lib/sidekiq/middleware/server/retry_jobs.rb +6 -0
- data/lib/sidekiq/middleware/server/timeout.rb +21 -0
- data/lib/sidekiq/processor.rb +2 -0
- data/lib/sidekiq/testing.rb +6 -0
- data/lib/sidekiq/testing/inline.rb +37 -0
- data/lib/sidekiq/version.rb +1 -1
- data/lib/sidekiq/web.rb +13 -16
- data/lib/sidekiq/worker.rb +3 -0
- data/lib/sidekiq/yaml_patch.rb +21 -0
- data/myapp/app/workers/hard_worker.rb +1 -0
- data/sidekiq.gemspec +1 -1
- data/test/helper.rb +1 -0
- data/test/test_client.rb +1 -2
- data/test/test_extensions.rb +2 -1
- data/test/test_manager.rb +3 -2
- data/test/test_retry.rb +29 -0
- data/test/test_testing.rb +38 -6
- data/test/test_testing_inline.rb +75 -0
- data/test/test_web.rb +21 -0
- data/web/assets/stylesheets/application.css +14 -2
- data/web/views/index.slim +5 -3
- data/web/views/retry.slim +17 -9
- metadata +30 -25
data/COMM-LICENSE
CHANGED
@@ -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 (“
|
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
data/bin/sidekiqctl
CHANGED
@@ -12,7 +12,7 @@ class Sidekiqctl
|
|
12
12
|
@timeout = timeout
|
13
13
|
|
14
14
|
done 'No pidfile given' if !pidfile
|
15
|
-
done
|
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
|
data/lib/sidekiq.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
97
|
-
MultiJson.dump(object)
|
98
|
-
else
|
99
|
-
MultiJson.encode(object)
|
100
|
-
end
|
90
|
+
MultiJson.encode(object)
|
101
91
|
end
|
102
92
|
|
103
93
|
end
|
data/lib/sidekiq/cli.rb
CHANGED
@@ -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
|
data/lib/sidekiq/client.rb
CHANGED
@@ -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
|
-
|
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
|
data/lib/sidekiq/processor.rb
CHANGED
@@ -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
|
|
data/lib/sidekiq/testing.rb
CHANGED
@@ -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
|
data/lib/sidekiq/version.rb
CHANGED
data/lib/sidekiq/web.rb
CHANGED
@@ -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,
|
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
|
|
data/lib/sidekiq/worker.rb
CHANGED
@@ -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
|
data/sidekiq.gemspec
CHANGED
@@ -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
|
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'
|
data/test/helper.rb
CHANGED
data/test/test_client.rb
CHANGED
data/test/test_extensions.rb
CHANGED
@@ -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
|
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
|
data/test/test_manager.rb
CHANGED
@@ -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
|
-
|
30
|
-
|
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)
|
data/test/test_retry.rb
CHANGED
@@ -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
|
data/test/test_testing.rb
CHANGED
@@ -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
|
-
|
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
|
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
|
data/test/test_web.rb
CHANGED
@@ -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
|
+
}
|
data/web/views/index.slim
CHANGED
@@ -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"
|
data/web/views/retry.slim
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
header
|
2
|
-
h1
|
2
|
+
h1 Job
|
3
3
|
|
4
|
-
-
|
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}" ← 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.
|
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-
|
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: &
|
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: *
|
24
|
+
version_requirements: *70181602671160
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: redis-namespace
|
27
|
-
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: *
|
35
|
+
version_requirements: *70181602670700
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: connection_pool
|
38
|
-
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: *
|
46
|
+
version_requirements: *70181602669980
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: celluloid
|
49
|
-
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: *
|
57
|
+
version_requirements: *70181602669040
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: multi_json
|
60
|
-
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
|
65
|
+
version: '1'
|
66
66
|
type: :runtime
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *70181602668580
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: minitest
|
71
|
-
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: *
|
79
|
+
version_requirements: *70181602684540
|
80
80
|
- !ruby/object:Gem::Dependency
|
81
81
|
name: sinatra
|
82
|
-
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: *
|
90
|
+
version_requirements: *70181602683860
|
91
91
|
- !ruby/object:Gem::Dependency
|
92
92
|
name: slim
|
93
|
-
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: *
|
101
|
+
version_requirements: *70181602683240
|
102
102
|
- !ruby/object:Gem::Dependency
|
103
103
|
name: rake
|
104
|
-
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: *
|
112
|
+
version_requirements: *70181602682820
|
113
113
|
- !ruby/object:Gem::Dependency
|
114
114
|
name: actionmailer
|
115
|
-
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: *
|
123
|
+
version_requirements: *70181602682300
|
124
124
|
- !ruby/object:Gem::Dependency
|
125
125
|
name: activerecord
|
126
|
-
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: *
|
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
|