sidekiq 0.10.0 → 0.10.1
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/Changes.md +7 -0
- data/bin/sidekiqctl +61 -30
- data/config.ru +10 -0
- data/lib/sidekiq.rb +5 -22
- data/lib/sidekiq/capistrano.rb +3 -3
- data/lib/sidekiq/processor.rb +0 -4
- data/lib/sidekiq/version.rb +1 -1
- data/lib/sidekiq/web.rb +52 -0
- data/test/test_client.rb +3 -3
- data/test/test_extensions.rb +5 -5
- data/test/test_manager.rb +1 -1
- data/test/test_stats.rb +1 -1
- data/test/test_web.rb +1 -1
- data/web/assets/javascripts/application.js +6 -0
- data/web/assets/javascripts/vendor/jquery.timeago.js +148 -0
- data/web/views/index.slim +7 -2
- data/web/views/retry.slim +44 -0
- metadata +26 -24
data/Changes.md
CHANGED
data/bin/sidekiqctl
CHANGED
@@ -2,42 +2,73 @@
|
|
2
2
|
|
3
3
|
require 'fileutils'
|
4
4
|
|
5
|
-
|
6
|
-
pidfile = ARGV[1]
|
7
|
-
timeout = ARGV[2].to_i
|
8
|
-
timeout = 10 if timeout == 0
|
5
|
+
class Sidekiqctl
|
9
6
|
|
10
|
-
|
11
|
-
puts msg
|
12
|
-
exit(0)
|
13
|
-
end
|
7
|
+
attr_reader :stage, :pidfile, :timeout
|
14
8
|
|
15
|
-
|
16
|
-
|
9
|
+
def initialize(stage, pidfile, timeout)
|
10
|
+
@stage = stage
|
11
|
+
@pidfile = pidfile
|
12
|
+
@timeout = timeout
|
17
13
|
|
18
|
-
|
19
|
-
done '
|
14
|
+
done 'No pidfile given' if !pidfile
|
15
|
+
done 'Pidfile does not exist' if !File.exist?(pidfile)
|
16
|
+
done 'Invalid pidfile content' if pid == 0
|
20
17
|
|
21
|
-
|
22
|
-
Process.getpgid(pid)
|
23
|
-
rescue Errno::ESRCH
|
24
|
-
done "Process doesn't exist"
|
25
|
-
end
|
18
|
+
fetch_process
|
26
19
|
|
27
|
-
case stage
|
28
|
-
when 'quiet'
|
29
|
-
`kill -USR1 #{pid}`
|
30
|
-
when 'stop'
|
31
|
-
`kill -TERM #{pid}`
|
32
|
-
timeout.times do
|
33
20
|
begin
|
34
|
-
|
35
|
-
rescue
|
36
|
-
|
37
|
-
|
21
|
+
send(stage)
|
22
|
+
rescue NoMethodError
|
23
|
+
done 'Invalid control command'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def fetch_process
|
28
|
+
Process.getpgid(pid)
|
29
|
+
rescue Errno::ESRCH
|
30
|
+
done "Process doesn't exist"
|
31
|
+
end
|
32
|
+
|
33
|
+
def done(msg)
|
34
|
+
puts msg
|
35
|
+
exit(0)
|
36
|
+
end
|
37
|
+
|
38
|
+
def pid
|
39
|
+
File.read(pidfile).to_i
|
40
|
+
end
|
41
|
+
|
42
|
+
def quiet
|
43
|
+
`kill -USR1 #{pid}`
|
44
|
+
end
|
45
|
+
|
46
|
+
def stop
|
47
|
+
`kill -TERM #{pid}`
|
48
|
+
timeout.times do
|
49
|
+
begin
|
50
|
+
Process.getpgid(pid)
|
51
|
+
rescue Errno::ESRCH
|
52
|
+
FileUtils.rm_f pidfile
|
53
|
+
done 'Sidekiq shut down gracefully.'
|
54
|
+
end
|
55
|
+
sleep 1
|
38
56
|
end
|
39
|
-
|
57
|
+
`kill -9 #{pid}`
|
58
|
+
FileUtils.rm_f pidfile
|
59
|
+
done 'Sidekiq shut down forcefully.'
|
40
60
|
end
|
41
|
-
|
42
|
-
|
61
|
+
|
62
|
+
def shutdown
|
63
|
+
quiet
|
64
|
+
stop
|
65
|
+
end
|
66
|
+
|
43
67
|
end
|
68
|
+
|
69
|
+
stage = ARGV[0]
|
70
|
+
pidfile = ARGV[1]
|
71
|
+
timeout = ARGV[2].to_i
|
72
|
+
timeout = 10 if timeout == 0
|
73
|
+
|
74
|
+
Sidekiqctl.new(stage, pidfile, timeout)
|
data/config.ru
CHANGED
@@ -4,5 +4,15 @@ Sidekiq.configure_client do |config|
|
|
4
4
|
config.redis = { :size => 1 }
|
5
5
|
end
|
6
6
|
|
7
|
+
#Sidekiq.redis {|conn| conn.flushdb }
|
8
|
+
#10.times do |idx|
|
9
|
+
#Sidekiq::Client.push('class' => 'HardWorker', 'args' => ['foo', 0.1, idx])
|
10
|
+
#end
|
11
|
+
|
12
|
+
#Sidekiq.redis { |conn| conn.zadd('retry', Time.now.utc.to_f + 3000, MultiJson.encode({
|
13
|
+
#'class' => 'HardWorker', 'args' => ['foo', 0.1, Time.now.to_f],
|
14
|
+
#'queue' => 'default', 'error_message' => 'No such method', 'error_class' => 'NoMethodError',
|
15
|
+
#'failed_at' => Time.now.utc, 'retry_count' => 0 })) }
|
16
|
+
|
7
17
|
require 'sidekiq/web'
|
8
18
|
run Sidekiq::Web
|
data/lib/sidekiq.rb
CHANGED
@@ -56,32 +56,15 @@ module Sidekiq
|
|
56
56
|
|
57
57
|
def self.redis(&block)
|
58
58
|
@redis ||= Sidekiq::RedisConnection.create
|
59
|
-
if
|
60
|
-
|
61
|
-
else
|
62
|
-
Sidekiq::Util.logger.info "*****************************************************
|
63
|
-
Sidekiq.redis now takes a block:
|
64
|
-
|
65
|
-
Sidekiq.redis { |connection| connection.smembers('myset') }
|
66
|
-
|
67
|
-
Please update your code accordingly.
|
68
|
-
Called from #{caller[0]}
|
69
|
-
*****************************************************"
|
70
|
-
@redis
|
71
|
-
end
|
59
|
+
raise ArgumentError, "requires a block" if !block
|
60
|
+
@redis.with(&block)
|
72
61
|
end
|
73
62
|
|
74
63
|
def self.redis=(hash)
|
75
|
-
|
76
|
-
RedisConnection.create(hash)
|
64
|
+
if hash.is_a?(Hash)
|
65
|
+
@redis = RedisConnection.create(hash)
|
77
66
|
else
|
78
|
-
|
79
|
-
Sidekiq.redis now takes a Hash:
|
80
|
-
old: Sidekiq.redis = Sidekiq::RedisConnection.create(:url => 'redis://foo.com', :namespace => 'abc', :size => 12)
|
81
|
-
new: Sidekiq.redis = { :url => 'redis://foo.com', :namespace => 'xyz', :size => 12 }
|
82
|
-
Called from #{caller[0]}
|
83
|
-
*****************************************************"
|
84
|
-
hash
|
67
|
+
@redis = hash
|
85
68
|
end
|
86
69
|
end
|
87
70
|
|
data/lib/sidekiq/capistrano.rb
CHANGED
@@ -8,18 +8,18 @@ Capistrano::Configuration.instance.load do
|
|
8
8
|
|
9
9
|
desc "Quiet sidekiq (stop accepting new work)"
|
10
10
|
task :quiet do
|
11
|
-
run "cd #{current_path} && sidekiqctl quiet #{current_path}/tmp/pids/sidekiq.pid"
|
11
|
+
run "cd #{current_path} && bundle exec sidekiqctl quiet #{current_path}/tmp/pids/sidekiq.pid"
|
12
12
|
end
|
13
13
|
|
14
14
|
desc "Stop sidekiq"
|
15
15
|
task :stop do
|
16
|
-
run "cd #{current_path} && sidekiqctl stop #{current_path}/tmp/pids/sidekiq.pid #{fetch :sidekiq_timeout}"
|
16
|
+
run "cd #{current_path} && bundle exec sidekiqctl stop #{current_path}/tmp/pids/sidekiq.pid #{fetch :sidekiq_timeout}"
|
17
17
|
end
|
18
18
|
|
19
19
|
desc "Start sidekiq"
|
20
20
|
task :start do
|
21
21
|
rails_env = fetch(:rails_env, "production")
|
22
|
-
run "cd #{current_path}
|
22
|
+
run "cd #{current_path} ; nohup bundle exec sidekiq -e #{rails_env} -C #{current_path}/config/sidekiq.yml -P #{current_path}/tmp/pids/sidekiq.pid >> #{current_path}/log/sidekiq.log 2>&1 &"
|
23
23
|
end
|
24
24
|
|
25
25
|
desc "Restart sidekiq"
|
data/lib/sidekiq/processor.rb
CHANGED
@@ -12,10 +12,6 @@ module Sidekiq
|
|
12
12
|
include Util
|
13
13
|
include Celluloid
|
14
14
|
|
15
|
-
def self.middleware
|
16
|
-
raise "Sidekiq::Processor.middleware is now Sidekiq.server_middleware"
|
17
|
-
end
|
18
|
-
|
19
15
|
def self.default_middleware
|
20
16
|
Middleware::Chain.new do |m|
|
21
17
|
m.add Middleware::Server::ExceptionHandler
|
data/lib/sidekiq/version.rb
CHANGED
data/lib/sidekiq/web.rb
CHANGED
@@ -36,6 +36,16 @@ module Sidekiq
|
|
36
36
|
use SprocketsMiddleware, :root => dir
|
37
37
|
|
38
38
|
helpers do
|
39
|
+
|
40
|
+
def reset_worker_list
|
41
|
+
Sidekiq.redis do |conn|
|
42
|
+
workers = conn.smembers('workers')
|
43
|
+
workers.each do |name|
|
44
|
+
conn.srem('workers', name) # if name =~ /:#{process_id}-/
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
39
49
|
def workers
|
40
50
|
@workers ||= begin
|
41
51
|
Sidekiq.redis do |conn|
|
@@ -75,6 +85,13 @@ module Sidekiq
|
|
75
85
|
end
|
76
86
|
end
|
77
87
|
|
88
|
+
def retries_with_score(score)
|
89
|
+
Sidekiq.redis do |conn|
|
90
|
+
results = conn.zrangebyscore('retry', score, score)
|
91
|
+
results.map { |msg| MultiJson.decode(msg) }
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
78
95
|
def location
|
79
96
|
Sidekiq.redis { |conn| conn.client.location }
|
80
97
|
end
|
@@ -88,18 +105,53 @@ module Sidekiq
|
|
88
105
|
return 'idle' if workers.size > 0 && workers.map { |x| x[1] }.compact.size == 0
|
89
106
|
return 'active'
|
90
107
|
end
|
108
|
+
|
109
|
+
def relative_time(time)
|
110
|
+
"<time datetime=\"#{time.getutc.iso8601}\">#{time}</time>"
|
111
|
+
end
|
91
112
|
end
|
92
113
|
|
93
114
|
get "/" do
|
94
115
|
slim :index
|
95
116
|
end
|
96
117
|
|
118
|
+
post "/reset" do
|
119
|
+
reset_worker_list
|
120
|
+
redirect root_path
|
121
|
+
end
|
122
|
+
|
97
123
|
get "/queues/:name" do
|
98
124
|
halt 404 unless params[:name]
|
99
125
|
@name = params[:name]
|
100
126
|
@messages = Sidekiq.redis {|conn| conn.lrange("queue:#{@name}", 0, 10) }.map { |str| MultiJson.decode(str) }
|
101
127
|
slim :queue
|
102
128
|
end
|
129
|
+
|
130
|
+
get "/retries/:score" do
|
131
|
+
halt 404 unless params[:score]
|
132
|
+
@score = params[:score].to_f
|
133
|
+
slim :retry
|
134
|
+
end
|
135
|
+
|
136
|
+
post "/retries/:score" do
|
137
|
+
halt 404 unless params[:score]
|
138
|
+
score = params[:score].to_f
|
139
|
+
if params['retry']
|
140
|
+
Sidekiq.redis do |conn|
|
141
|
+
results = conn.zrangebyscore('retry', score, score)
|
142
|
+
conn.zremrangebyscore('retry', score, score)
|
143
|
+
results.map do |message|
|
144
|
+
msg = MultiJson.decode(message)
|
145
|
+
conn.rpush("queue:#{msg['queue']}", message)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
elsif params['delete']
|
149
|
+
Sidekiq.redis do |conn|
|
150
|
+
conn.zremrangebyscore('retry', score, score)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
redirect root_path
|
154
|
+
end
|
103
155
|
end
|
104
156
|
|
105
157
|
end
|
data/test/test_client.rb
CHANGED
@@ -6,7 +6,7 @@ class TestClient < MiniTest::Unit::TestCase
|
|
6
6
|
describe 'with real redis' do
|
7
7
|
before do
|
8
8
|
Sidekiq.redis = REDIS
|
9
|
-
Sidekiq.redis.flushdb
|
9
|
+
Sidekiq.redis {|c| c.flushdb }
|
10
10
|
end
|
11
11
|
|
12
12
|
it 'does not push duplicate messages when configured for unique only' do
|
@@ -15,13 +15,13 @@ class TestClient < MiniTest::Unit::TestCase
|
|
15
15
|
chain.add Sidekiq::Middleware::Client::UniqueJobs
|
16
16
|
end
|
17
17
|
10.times { Sidekiq::Client.push('customqueue', 'class' => 'Foo', 'args' => [1, 2]) }
|
18
|
-
assert_equal 1, Sidekiq.redis.llen("queue:customqueue")
|
18
|
+
assert_equal 1, Sidekiq.redis {|c| c.llen("queue:customqueue") }
|
19
19
|
end
|
20
20
|
|
21
21
|
it 'does push duplicate messages when not configured for unique only' do
|
22
22
|
Sidekiq.client_middleware.remove(Sidekiq::Middleware::Client::UniqueJobs)
|
23
23
|
10.times { Sidekiq::Client.push('customqueue2', 'class' => 'Foo', 'args' => [1, 2]) }
|
24
|
-
assert_equal 10, Sidekiq.redis.llen("queue:customqueue2")
|
24
|
+
assert_equal 10, Sidekiq.redis {|c| c.llen("queue:customqueue2") }
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
data/test/test_extensions.rb
CHANGED
@@ -11,7 +11,7 @@ class TestExtensions < MiniTest::Unit::TestCase
|
|
11
11
|
describe 'sidekiq extensions' do
|
12
12
|
before do
|
13
13
|
Sidekiq.redis = REDIS
|
14
|
-
Sidekiq.redis.flushdb
|
14
|
+
Sidekiq.redis {|c| c.flushdb }
|
15
15
|
end
|
16
16
|
|
17
17
|
class MyModel < ActiveRecord::Base
|
@@ -22,10 +22,10 @@ class TestExtensions < MiniTest::Unit::TestCase
|
|
22
22
|
|
23
23
|
it 'allows delayed exection of ActiveRecord class methods' do
|
24
24
|
assert_equal [], Sidekiq::Client.registered_queues
|
25
|
-
assert_equal 0, Sidekiq.redis.llen('queue:default')
|
25
|
+
assert_equal 0, Sidekiq.redis {|c| c.llen('queue:default') }
|
26
26
|
MyModel.delay.long_class_method
|
27
27
|
assert_equal ['default'], Sidekiq::Client.registered_queues
|
28
|
-
assert_equal 1, Sidekiq.redis.llen('queue:default')
|
28
|
+
assert_equal 1, Sidekiq.redis {|c| c.llen('queue:default') }
|
29
29
|
end
|
30
30
|
|
31
31
|
class UserMailer < ActionMailer::Base
|
@@ -36,10 +36,10 @@ class TestExtensions < MiniTest::Unit::TestCase
|
|
36
36
|
|
37
37
|
it 'allows delayed delivery of ActionMailer mails' do
|
38
38
|
assert_equal [], Sidekiq::Client.registered_queues
|
39
|
-
assert_equal 0, Sidekiq.redis.llen('queue:default')
|
39
|
+
assert_equal 0, Sidekiq.redis {|c| c.llen('queue:default') }
|
40
40
|
UserMailer.delay.greetings(1, 2)
|
41
41
|
assert_equal ['default'], Sidekiq::Client.registered_queues
|
42
|
-
assert_equal 1, Sidekiq.redis.llen('queue:default')
|
42
|
+
assert_equal 1, Sidekiq.redis {|c| c.llen('queue:default') }
|
43
43
|
end
|
44
44
|
end
|
45
45
|
|
data/test/test_manager.rb
CHANGED
data/test/test_stats.rb
CHANGED
data/test/test_web.rb
CHANGED
@@ -0,0 +1,148 @@
|
|
1
|
+
/**
|
2
|
+
* Timeago is a jQuery plugin that makes it easy to support automatically
|
3
|
+
* updating fuzzy timestamps (e.g. "4 minutes ago" or "about 1 day ago").
|
4
|
+
*
|
5
|
+
* @name timeago
|
6
|
+
* @version 0.11.1
|
7
|
+
* @requires jQuery v1.2.3+
|
8
|
+
* @author Ryan McGeary
|
9
|
+
* @license MIT License - http://www.opensource.org/licenses/mit-license.php
|
10
|
+
*
|
11
|
+
* For usage and examples, visit:
|
12
|
+
* http://timeago.yarp.com/
|
13
|
+
*
|
14
|
+
* Copyright (c) 2008-2011, Ryan McGeary (ryanonjavascript -[at]- mcgeary [*dot*] org)
|
15
|
+
*/
|
16
|
+
(function($) {
|
17
|
+
$.timeago = function(timestamp) {
|
18
|
+
if (timestamp instanceof Date) {
|
19
|
+
return inWords(timestamp);
|
20
|
+
} else if (typeof timestamp === "string") {
|
21
|
+
return inWords($.timeago.parse(timestamp));
|
22
|
+
} else {
|
23
|
+
return inWords($.timeago.datetime(timestamp));
|
24
|
+
}
|
25
|
+
};
|
26
|
+
var $t = $.timeago;
|
27
|
+
|
28
|
+
$.extend($.timeago, {
|
29
|
+
settings: {
|
30
|
+
refreshMillis: 60000,
|
31
|
+
allowFuture: false,
|
32
|
+
strings: {
|
33
|
+
prefixAgo: null,
|
34
|
+
prefixFromNow: null,
|
35
|
+
suffixAgo: "ago",
|
36
|
+
suffixFromNow: "from now",
|
37
|
+
seconds: "less than a minute",
|
38
|
+
minute: "about a minute",
|
39
|
+
minutes: "%d minutes",
|
40
|
+
hour: "about an hour",
|
41
|
+
hours: "about %d hours",
|
42
|
+
day: "a day",
|
43
|
+
days: "%d days",
|
44
|
+
month: "about a month",
|
45
|
+
months: "%d months",
|
46
|
+
year: "about a year",
|
47
|
+
years: "%d years",
|
48
|
+
wordSeparator: " ",
|
49
|
+
numbers: []
|
50
|
+
}
|
51
|
+
},
|
52
|
+
inWords: function(distanceMillis) {
|
53
|
+
var $l = this.settings.strings;
|
54
|
+
var prefix = $l.prefixAgo;
|
55
|
+
var suffix = $l.suffixAgo;
|
56
|
+
if (this.settings.allowFuture) {
|
57
|
+
if (distanceMillis < 0) {
|
58
|
+
prefix = $l.prefixFromNow;
|
59
|
+
suffix = $l.suffixFromNow;
|
60
|
+
}
|
61
|
+
}
|
62
|
+
|
63
|
+
var seconds = Math.abs(distanceMillis) / 1000;
|
64
|
+
var minutes = seconds / 60;
|
65
|
+
var hours = minutes / 60;
|
66
|
+
var days = hours / 24;
|
67
|
+
var years = days / 365;
|
68
|
+
|
69
|
+
function substitute(stringOrFunction, number) {
|
70
|
+
var string = $.isFunction(stringOrFunction) ? stringOrFunction(number, distanceMillis) : stringOrFunction;
|
71
|
+
var value = ($l.numbers && $l.numbers[number]) || number;
|
72
|
+
return string.replace(/%d/i, value);
|
73
|
+
}
|
74
|
+
|
75
|
+
var words = seconds < 45 && substitute($l.seconds, Math.round(seconds)) ||
|
76
|
+
seconds < 90 && substitute($l.minute, 1) ||
|
77
|
+
minutes < 45 && substitute($l.minutes, Math.round(minutes)) ||
|
78
|
+
minutes < 90 && substitute($l.hour, 1) ||
|
79
|
+
hours < 24 && substitute($l.hours, Math.round(hours)) ||
|
80
|
+
hours < 42 && substitute($l.day, 1) ||
|
81
|
+
days < 30 && substitute($l.days, Math.round(days)) ||
|
82
|
+
days < 45 && substitute($l.month, 1) ||
|
83
|
+
days < 365 && substitute($l.months, Math.round(days / 30)) ||
|
84
|
+
years < 1.5 && substitute($l.year, 1) ||
|
85
|
+
substitute($l.years, Math.round(years));
|
86
|
+
|
87
|
+
var separator = $l.wordSeparator === undefined ? " " : $l.wordSeparator;
|
88
|
+
return $.trim([prefix, words, suffix].join(separator));
|
89
|
+
},
|
90
|
+
parse: function(iso8601) {
|
91
|
+
var s = $.trim(iso8601);
|
92
|
+
s = s.replace(/\.\d\d\d+/,""); // remove milliseconds
|
93
|
+
s = s.replace(/-/,"/").replace(/-/,"/");
|
94
|
+
s = s.replace(/T/," ").replace(/Z/," UTC");
|
95
|
+
s = s.replace(/([\+\-]\d\d)\:?(\d\d)/," $1$2"); // -04:00 -> -0400
|
96
|
+
return new Date(s);
|
97
|
+
},
|
98
|
+
datetime: function(elem) {
|
99
|
+
// jQuery's `is()` doesn't play well with HTML5 in IE
|
100
|
+
var isTime = $(elem).get(0).tagName.toLowerCase() === "time"; // $(elem).is("time");
|
101
|
+
var iso8601 = isTime ? $(elem).attr("datetime") : $(elem).attr("title");
|
102
|
+
return $t.parse(iso8601);
|
103
|
+
}
|
104
|
+
});
|
105
|
+
|
106
|
+
$.fn.timeago = function() {
|
107
|
+
var self = this;
|
108
|
+
self.each(refresh);
|
109
|
+
|
110
|
+
var $s = $t.settings;
|
111
|
+
if ($s.refreshMillis > 0) {
|
112
|
+
setInterval(function() { self.each(refresh); }, $s.refreshMillis);
|
113
|
+
}
|
114
|
+
return self;
|
115
|
+
};
|
116
|
+
|
117
|
+
function refresh() {
|
118
|
+
var data = prepareData(this);
|
119
|
+
if (!isNaN(data.datetime)) {
|
120
|
+
$(this).text(inWords(data.datetime));
|
121
|
+
}
|
122
|
+
return this;
|
123
|
+
}
|
124
|
+
|
125
|
+
function prepareData(element) {
|
126
|
+
element = $(element);
|
127
|
+
if (!element.data("timeago")) {
|
128
|
+
element.data("timeago", { datetime: $t.datetime(element) });
|
129
|
+
var text = $.trim(element.text());
|
130
|
+
if (text.length > 0) {
|
131
|
+
element.attr("title", text);
|
132
|
+
}
|
133
|
+
}
|
134
|
+
return element.data("timeago");
|
135
|
+
}
|
136
|
+
|
137
|
+
function inWords(date) {
|
138
|
+
return $t.inWords(distance(date));
|
139
|
+
}
|
140
|
+
|
141
|
+
function distance(date) {
|
142
|
+
return (new Date().getTime() - date.getTime());
|
143
|
+
}
|
144
|
+
|
145
|
+
// fix for IE6 suckage
|
146
|
+
document.createElement("abbr");
|
147
|
+
document.createElement("time");
|
148
|
+
}(jQuery));
|
data/web/views/index.slim
CHANGED
@@ -22,6 +22,7 @@
|
|
22
22
|
th Queue
|
23
23
|
th Class
|
24
24
|
th Arguments
|
25
|
+
th Started
|
25
26
|
- workers.each do |(worker, msg)|
|
26
27
|
tr
|
27
28
|
td= worker
|
@@ -29,8 +30,11 @@
|
|
29
30
|
td= msg['queue']
|
30
31
|
td= msg['payload']['class']
|
31
32
|
td= msg['payload']['args'].inspect[0..100]
|
33
|
+
td== relative_time(Time.parse(msg['run_at']))
|
32
34
|
- else
|
33
|
-
td colspan=
|
35
|
+
td colspan=4 Idle
|
36
|
+
form action="#{root_path}reset" method="post"
|
37
|
+
button.btn type="submit" Clear worker list
|
34
38
|
|
35
39
|
#queues.tab-pane
|
36
40
|
table class="table table-striped table-bordered"
|
@@ -53,7 +57,8 @@
|
|
53
57
|
th Args
|
54
58
|
- retries.each do |(msg, score)|
|
55
59
|
tr
|
56
|
-
td
|
60
|
+
td
|
61
|
+
a href="retries/#{score}"== relative_time(Time.at(score))
|
57
62
|
td= msg['retry_count']
|
58
63
|
td
|
59
64
|
a href="queues/#{msg['queue']}" #{msg['queue']}
|
@@ -0,0 +1,44 @@
|
|
1
|
+
header
|
2
|
+
h1 Retry Job
|
3
|
+
|
4
|
+
- retries_with_score(@score).each do |msg|
|
5
|
+
table class="table table-striped table-bordered"
|
6
|
+
tbody
|
7
|
+
tr
|
8
|
+
th Queue
|
9
|
+
td
|
10
|
+
a href="#{root_path}queues/#{msg['queue']}" #{msg['queue']}
|
11
|
+
tr
|
12
|
+
th Job Class
|
13
|
+
td
|
14
|
+
code= msg['class']
|
15
|
+
tr
|
16
|
+
th Job Arguments
|
17
|
+
td
|
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
|
+
- if msg['retry_count'] > 0
|
27
|
+
tr
|
28
|
+
th Retry Count
|
29
|
+
td= msg['retry_count']
|
30
|
+
tr
|
31
|
+
th Last Retry
|
32
|
+
td== relative_time(Time.parse(msg['retried_at']))
|
33
|
+
- else
|
34
|
+
tr
|
35
|
+
th Originally Failed
|
36
|
+
td== relative_time(Time.parse(msg['failed_at']))
|
37
|
+
tr
|
38
|
+
th Next Retry
|
39
|
+
td== relative_time(Time.at(@score))
|
40
|
+
|
41
|
+
form.form-horizontal action="#{root_path}retries/#{@score}" method="post"
|
42
|
+
a.btn href="#{root_path}" ← Back
|
43
|
+
input.btn.btn-primary type="submit" name="retry" value="Retry Now"
|
44
|
+
input.btn.btn-danger type="submit" name="delete" value="Delete"
|
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: 0.10.
|
4
|
+
version: 0.10.1
|
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-03-
|
12
|
+
date: 2012-03-30 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: redis
|
16
|
-
requirement: &
|
16
|
+
requirement: &70182756998440 !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: *70182756998440
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: redis-namespace
|
27
|
-
requirement: &
|
27
|
+
requirement: &70182756997620 !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: *70182756997620
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: connection_pool
|
38
|
-
requirement: &
|
38
|
+
requirement: &70182756997120 !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: *70182756997120
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: celluloid
|
49
|
-
requirement: &
|
49
|
+
requirement: &70182756996700 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ! '>='
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: '0'
|
55
55
|
type: :runtime
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *70182756996700
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: multi_json
|
60
|
-
requirement: &
|
60
|
+
requirement: &70182756996240 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ! '>='
|
@@ -65,10 +65,10 @@ dependencies:
|
|
65
65
|
version: '0'
|
66
66
|
type: :runtime
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *70182756996240
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: minitest
|
71
|
-
requirement: &
|
71
|
+
requirement: &70182757019360 !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: *70182757019360
|
80
80
|
- !ruby/object:Gem::Dependency
|
81
81
|
name: sinatra
|
82
|
-
requirement: &
|
82
|
+
requirement: &70182757018940 !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: *70182757018940
|
91
91
|
- !ruby/object:Gem::Dependency
|
92
92
|
name: slim
|
93
|
-
requirement: &
|
93
|
+
requirement: &70182757018520 !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: *70182757018520
|
102
102
|
- !ruby/object:Gem::Dependency
|
103
103
|
name: rake
|
104
|
-
requirement: &
|
104
|
+
requirement: &70182757018100 !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: *70182757018100
|
113
113
|
- !ruby/object:Gem::Dependency
|
114
114
|
name: actionmailer
|
115
|
-
requirement: &
|
115
|
+
requirement: &70182757017600 !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: *70182757017600
|
124
124
|
- !ruby/object:Gem::Dependency
|
125
125
|
name: activerecord
|
126
|
-
requirement: &
|
126
|
+
requirement: &70182757017040 !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: *70182757017040
|
135
135
|
description: Simple, efficient message processing for Ruby
|
136
136
|
email:
|
137
137
|
- mperham@gmail.com
|
@@ -261,12 +261,14 @@ files:
|
|
261
261
|
- web/assets/javascripts/vendor/bootstrap/bootstrap-transition.js
|
262
262
|
- web/assets/javascripts/vendor/bootstrap/bootstrap-typeahead.js
|
263
263
|
- web/assets/javascripts/vendor/jquery.js
|
264
|
+
- web/assets/javascripts/vendor/jquery.timeago.js
|
264
265
|
- web/assets/stylesheets/application.css
|
265
266
|
- web/assets/stylesheets/vendor/bootstrap-responsive.css
|
266
267
|
- web/assets/stylesheets/vendor/bootstrap.css
|
267
268
|
- web/views/index.slim
|
268
269
|
- web/views/layout.slim
|
269
270
|
- web/views/queue.slim
|
271
|
+
- web/views/retry.slim
|
270
272
|
homepage: http://mperham.github.com/sidekiq
|
271
273
|
licenses: []
|
272
274
|
post_install_message:
|