sidekiq 0.8.0 → 0.9.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/Changes.md +11 -0
- data/Gemfile +7 -1
- data/LICENSE +7 -1
- data/README.md +2 -0
- data/TODO.md +1 -2
- data/bin/sidekiq +1 -1
- data/config.ru +8 -0
- data/examples/config.yml +0 -2
- data/examples/scheduling.rb +37 -0
- data/lib/sidekiq.rb +25 -11
- data/lib/sidekiq/capistrano.rb +8 -5
- data/lib/sidekiq/cli.rb +20 -21
- data/lib/sidekiq/client.rb +9 -6
- data/lib/sidekiq/extensions/action_mailer.rb +1 -2
- data/lib/sidekiq/extensions/active_record.rb +1 -3
- data/lib/sidekiq/extensions/generic_proxy.rb +1 -1
- data/lib/sidekiq/manager.rb +28 -22
- data/lib/sidekiq/middleware/client/unique_jobs.rb +3 -3
- data/lib/sidekiq/middleware/server/failure_jobs.rb +1 -1
- data/lib/sidekiq/middleware/server/unique_jobs.rb +1 -1
- data/lib/sidekiq/processor.rb +4 -6
- data/lib/sidekiq/rails.rb +16 -1
- data/lib/sidekiq/redis_connection.rb +3 -3
- data/lib/sidekiq/util.rb +3 -15
- data/lib/sidekiq/version.rb +1 -1
- data/lib/sidekiq/web.rb +93 -0
- data/lib/sidekiq/worker.rb +0 -4
- data/myapp/Gemfile +15 -3
- data/myapp/app/controllers/work_controller.rb +1 -1
- data/myapp/config/initializers/sidekiq.rb +2 -2
- data/myapp/config/routes.rb +2 -2
- data/sidekiq.gemspec +3 -1
- data/test/helper.rb +4 -0
- data/test/test_cli.rb +26 -14
- data/test/test_client.rb +2 -2
- data/test/test_extensions.rb +11 -7
- data/test/test_manager.rb +2 -3
- data/test/test_middleware.rb +1 -1
- data/test/test_stats.rb +28 -29
- data/test/test_testing.rb +47 -14
- data/test/test_web.rb +51 -0
- data/web/assets/images/bootstrap/glyphicons-halflings-white.png +0 -0
- data/web/assets/images/bootstrap/glyphicons-halflings.png +0 -0
- data/web/assets/javascripts/application.js +3 -0
- data/web/assets/javascripts/vendor/bootstrap.js +12 -0
- data/web/assets/javascripts/vendor/bootstrap/bootstrap-alert.js +91 -0
- data/web/assets/javascripts/vendor/bootstrap/bootstrap-button.js +98 -0
- data/web/assets/javascripts/vendor/bootstrap/bootstrap-carousel.js +154 -0
- data/web/assets/javascripts/vendor/bootstrap/bootstrap-collapse.js +136 -0
- data/web/assets/javascripts/vendor/bootstrap/bootstrap-dropdown.js +92 -0
- data/web/assets/javascripts/vendor/bootstrap/bootstrap-modal.js +210 -0
- data/web/assets/javascripts/vendor/bootstrap/bootstrap-popover.js +95 -0
- data/web/assets/javascripts/vendor/bootstrap/bootstrap-scrollspy.js +125 -0
- data/web/assets/javascripts/vendor/bootstrap/bootstrap-tab.js +130 -0
- data/web/assets/javascripts/vendor/bootstrap/bootstrap-tooltip.js +270 -0
- data/web/assets/javascripts/vendor/bootstrap/bootstrap-transition.js +51 -0
- data/web/assets/javascripts/vendor/bootstrap/bootstrap-typeahead.js +271 -0
- data/web/assets/javascripts/vendor/jquery.js +9266 -0
- data/web/assets/stylesheets/application.css +11 -0
- data/web/assets/stylesheets/vendor/bootstrap-responsive.css +567 -0
- data/web/assets/stylesheets/vendor/bootstrap.css +3365 -0
- data/web/views/index.slim +42 -0
- data/web/views/layout.slim +24 -0
- data/web/views/queue.slim +11 -0
- metadata +71 -22
- data/lib/sidekiq/middleware/client/resque_web_compatibility.rb +0 -14
@@ -9,9 +9,9 @@ module Sidekiq
|
|
9
9
|
|
10
10
|
def call(item, queue)
|
11
11
|
payload_hash = Digest::MD5.hexdigest(MultiJson.encode(item))
|
12
|
-
Sidekiq.redis
|
13
|
-
return if
|
14
|
-
|
12
|
+
Sidekiq.redis do |conn|
|
13
|
+
return if conn.get(payload_hash)
|
14
|
+
conn.setex(payload_hash, HASH_KEY_EXPIRATION, 1)
|
15
15
|
end
|
16
16
|
|
17
17
|
yield
|
data/lib/sidekiq/processor.rb
CHANGED
@@ -25,11 +25,9 @@ module Sidekiq
|
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
28
|
-
attr_accessor :msg, :queue
|
29
|
-
|
30
28
|
def initialize(boss)
|
31
29
|
@boss = boss
|
32
|
-
redis.sadd('workers', self)
|
30
|
+
redis {|x| x.sadd('workers', self) }
|
33
31
|
end
|
34
32
|
|
35
33
|
def process(msg, queue)
|
@@ -55,7 +53,7 @@ module Sidekiq
|
|
55
53
|
private
|
56
54
|
|
57
55
|
def stats(worker, msg, queue)
|
58
|
-
redis
|
56
|
+
redis do |conn|
|
59
57
|
conn.multi do
|
60
58
|
conn.set("worker:#{self}:started", Time.now.to_s)
|
61
59
|
conn.set("worker:#{self}", MultiJson.encode(:queue => queue, :payload => msg,
|
@@ -69,7 +67,7 @@ module Sidekiq
|
|
69
67
|
rescue
|
70
68
|
dying = true
|
71
69
|
# Uh oh, error. We will die so unregister as much as we can first.
|
72
|
-
redis
|
70
|
+
redis do |conn|
|
73
71
|
conn.multi do
|
74
72
|
conn.incrby("stat:failed", 1)
|
75
73
|
conn.del("stat:processed:#{self}")
|
@@ -78,7 +76,7 @@ module Sidekiq
|
|
78
76
|
end
|
79
77
|
raise
|
80
78
|
ensure
|
81
|
-
redis
|
79
|
+
redis do |conn|
|
82
80
|
conn.multi do
|
83
81
|
conn.del("worker:#{self}")
|
84
82
|
conn.del("worker:#{self}:started")
|
data/lib/sidekiq/rails.rb
CHANGED
@@ -1,5 +1,20 @@
|
|
1
1
|
module Sidekiq
|
2
|
+
def self.hook_rails!
|
3
|
+
if defined?(ActiveRecord)
|
4
|
+
ActiveRecord::Base.extend(Sidekiq::Extensions::ActiveRecord)
|
5
|
+
ActiveRecord::Base.send(:include, Sidekiq::Extensions::ActiveRecord)
|
6
|
+
end
|
7
|
+
|
8
|
+
if defined?(ActionMailer)
|
9
|
+
ActionMailer::Base.extend(Sidekiq::Extensions::ActionMailer)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
2
13
|
class Rails < ::Rails::Engine
|
3
14
|
config.autoload_paths << File.expand_path("#{config.root}/app/workers") if File.exist?("#{config.root}/app/workers")
|
4
|
-
|
15
|
+
|
16
|
+
initializer 'sidekiq' do
|
17
|
+
Sidekiq.hook_rails!
|
18
|
+
end
|
19
|
+
end if defined?(::Rails)
|
5
20
|
end
|
@@ -5,9 +5,9 @@ module Sidekiq
|
|
5
5
|
class RedisConnection
|
6
6
|
def self.create(options={})
|
7
7
|
url = options[:url] || ENV['REDISTOGO_URL'] || 'redis://localhost:6379/0'
|
8
|
-
|
9
|
-
|
10
|
-
|
8
|
+
ConnectionPool::Wrapper.new(:timeout => 1, :size => (options[:size] || Sidekiq.options[:concurrency] || 25)) do
|
9
|
+
build_client(url, options[:namespace])
|
10
|
+
end
|
11
11
|
end
|
12
12
|
|
13
13
|
def self.build_client(url, namespace)
|
data/lib/sidekiq/util.rb
CHANGED
@@ -50,24 +50,12 @@ module Sidekiq
|
|
50
50
|
Sidekiq::Util.logger
|
51
51
|
end
|
52
52
|
|
53
|
-
def redis
|
54
|
-
Sidekiq.redis
|
53
|
+
def redis(&block)
|
54
|
+
Sidekiq.redis(&block)
|
55
55
|
end
|
56
56
|
|
57
57
|
def process_id
|
58
|
-
|
59
|
-
end
|
60
|
-
|
61
|
-
def self.process_id
|
62
|
-
@pid ||= begin
|
63
|
-
if Process.pid == 1
|
64
|
-
# Heroku does not expose pids.
|
65
|
-
require 'securerandom'
|
66
|
-
(SecureRandom.random_number * 4_000_000_000).floor.to_s(16)
|
67
|
-
else
|
68
|
-
Process.pid
|
69
|
-
end
|
70
|
-
end
|
58
|
+
Process.pid
|
71
59
|
end
|
72
60
|
end
|
73
61
|
end
|
data/lib/sidekiq/version.rb
CHANGED
data/lib/sidekiq/web.rb
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
require 'sinatra/base'
|
2
|
+
require 'slim'
|
3
|
+
require 'sprockets'
|
4
|
+
|
5
|
+
module Sidekiq
|
6
|
+
class SprocketsMiddleware
|
7
|
+
def initialize(app, options={})
|
8
|
+
@app = app
|
9
|
+
@root = options[:root]
|
10
|
+
path = options[:path] || 'assets'
|
11
|
+
@matcher = /^\/#{path}\/*/
|
12
|
+
@environment = ::Sprockets::Environment.new(@root)
|
13
|
+
@environment.append_path 'assets/javascripts'
|
14
|
+
@environment.append_path 'assets/javascripts/vendor'
|
15
|
+
@environment.append_path 'assets/stylesheets'
|
16
|
+
@environment.append_path 'assets/stylesheets/vendor'
|
17
|
+
@environment.append_path 'assets/images'
|
18
|
+
end
|
19
|
+
|
20
|
+
def call(env)
|
21
|
+
# Solve the problem of people requesting /sidekiq when they need to request /sidekiq/ so
|
22
|
+
# that relative links in templates resolve correctly.
|
23
|
+
return [301, { 'Location' => "#{env['SCRIPT_NAME']}/" }, []] if env['SCRIPT_NAME'] == env['REQUEST_PATH']
|
24
|
+
|
25
|
+
return @app.call(env) unless @matcher =~ env["PATH_INFO"]
|
26
|
+
env['PATH_INFO'].sub!(@matcher,'')
|
27
|
+
@environment.call(env)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class Web < Sinatra::Base
|
32
|
+
dir = File.expand_path(File.dirname(__FILE__) + "/../../web")
|
33
|
+
set :views, "#{dir}/views"
|
34
|
+
set :root, "#{dir}/public"
|
35
|
+
set :slim, :pretty => true
|
36
|
+
use SprocketsMiddleware, :root => dir
|
37
|
+
|
38
|
+
helpers do
|
39
|
+
def workers
|
40
|
+
@workers ||= begin
|
41
|
+
Sidekiq.redis.with_connection do |conn|
|
42
|
+
conn.smembers('workers').map do |w|
|
43
|
+
msg = conn.get("worker:#{w}")
|
44
|
+
msg = MultiJson.decode(msg) if msg
|
45
|
+
[w, msg]
|
46
|
+
end.sort { |x| x[1] ? -1 : 1 }
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def processed
|
52
|
+
Sidekiq.redis.get('stat:processed') || 0
|
53
|
+
end
|
54
|
+
|
55
|
+
def failed
|
56
|
+
Sidekiq.redis.get('stat:failed') || 0
|
57
|
+
end
|
58
|
+
|
59
|
+
def queues
|
60
|
+
Sidekiq.redis.with_connection do |conn|
|
61
|
+
conn.smembers('queues').map do |q|
|
62
|
+
[q, conn.llen("queue:#{q}") || 0]
|
63
|
+
end.sort { |x,y| x[1] <=> y[1] }
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def location
|
68
|
+
Sidekiq.redis.client.location
|
69
|
+
end
|
70
|
+
|
71
|
+
def root_path
|
72
|
+
"#{env['SCRIPT_NAME']}/"
|
73
|
+
end
|
74
|
+
|
75
|
+
def status
|
76
|
+
return 'down' if workers.size == 0
|
77
|
+
return 'idle' if workers.size > 0 && workers.map { |x| x[1] }.compact.size == 0
|
78
|
+
return 'active'
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
get "/" do
|
83
|
+
slim :index
|
84
|
+
end
|
85
|
+
|
86
|
+
get "/queues/:name" do
|
87
|
+
@name = params[:name]
|
88
|
+
@messages = Sidekiq.redis.lrange("queue:#{@name}", 0, 10).map { |str| MultiJson.decode(str) }
|
89
|
+
slim :queue
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
data/lib/sidekiq/worker.rb
CHANGED
data/myapp/Gemfile
CHANGED
@@ -1,7 +1,19 @@
|
|
1
1
|
source 'https://rubygems.org'
|
2
2
|
|
3
|
-
|
4
|
-
gem 'sqlite3'
|
3
|
+
platforms :ruby do
|
4
|
+
gem 'sqlite3'
|
5
|
+
end
|
6
|
+
|
7
|
+
platforms :jruby do
|
8
|
+
gem 'jruby-openssl'
|
9
|
+
gem 'activerecord-jdbcsqlite3-adapter'
|
10
|
+
end
|
11
|
+
|
12
|
+
gem 'rails', '3.2.2'
|
5
13
|
gem 'sidekiq', :path => '..'
|
6
|
-
gem 'resque'
|
7
14
|
gem 'capistrano'
|
15
|
+
|
16
|
+
# sidekiq-web dependencies
|
17
|
+
gem 'slim'
|
18
|
+
gem 'sinatra'
|
19
|
+
gem 'sprockets'
|
data/myapp/config/routes.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
|
-
require '
|
1
|
+
require 'sidekiq/web'
|
2
2
|
|
3
3
|
Myapp::Application.routes.draw do
|
4
|
-
mount
|
4
|
+
mount Sidekiq::Web => '/sidekiq'
|
5
5
|
get "work" => "work#index"
|
6
6
|
get "work/email" => "work#email"
|
7
7
|
get "work/post" => "work#delayed_post"
|
data/sidekiq.gemspec
CHANGED
@@ -15,10 +15,12 @@ Gem::Specification.new do |gem|
|
|
15
15
|
gem.version = Sidekiq::VERSION
|
16
16
|
gem.add_dependency 'redis'
|
17
17
|
gem.add_dependency 'redis-namespace'
|
18
|
-
gem.add_dependency 'connection_pool'
|
18
|
+
gem.add_dependency 'connection_pool', '>= 0.9.0'
|
19
19
|
gem.add_dependency 'celluloid'
|
20
20
|
gem.add_dependency 'multi_json'
|
21
21
|
gem.add_development_dependency 'minitest'
|
22
|
+
gem.add_development_dependency 'sinatra'
|
23
|
+
gem.add_development_dependency 'slim'
|
22
24
|
gem.add_development_dependency 'rake'
|
23
25
|
gem.add_development_dependency 'actionmailer'
|
24
26
|
gem.add_development_dependency 'activerecord'
|
data/test/helper.rb
CHANGED
@@ -8,5 +8,9 @@ require 'minitest/unit'
|
|
8
8
|
require 'minitest/pride'
|
9
9
|
require 'minitest/autorun'
|
10
10
|
|
11
|
+
require 'sidekiq'
|
11
12
|
require 'sidekiq/util'
|
12
13
|
Sidekiq::Util.logger.level = Logger::ERROR
|
14
|
+
|
15
|
+
require 'sidekiq/redis_connection'
|
16
|
+
REDIS = Sidekiq::RedisConnection.create(:url => 'redis://localhost/sidekiq_test')
|
data/test/test_cli.rb
CHANGED
@@ -2,10 +2,20 @@ require 'helper'
|
|
2
2
|
require 'sidekiq/cli'
|
3
3
|
require 'tempfile'
|
4
4
|
|
5
|
+
cli = Sidekiq::CLI.instance
|
6
|
+
def cli.die(code)
|
7
|
+
@code = code
|
8
|
+
end
|
9
|
+
|
10
|
+
def cli.valid?
|
11
|
+
!@code
|
12
|
+
end
|
13
|
+
|
5
14
|
class TestCli < MiniTest::Unit::TestCase
|
6
15
|
describe 'with cli' do
|
16
|
+
|
7
17
|
before do
|
8
|
-
@cli =
|
18
|
+
@cli = Sidekiq::CLI.instance
|
9
19
|
end
|
10
20
|
|
11
21
|
it 'blows up with an invalid require' do
|
@@ -14,7 +24,7 @@ class TestCli < MiniTest::Unit::TestCase
|
|
14
24
|
end
|
15
25
|
end
|
16
26
|
|
17
|
-
it '
|
27
|
+
it 'requires the specified Ruby code' do
|
18
28
|
@cli.parse(['sidekiq', '-r', './test/fake_env.rb'])
|
19
29
|
assert($LOADED_FEATURES.any? { |x| x =~ /fake_env/ })
|
20
30
|
assert @cli.valid?
|
@@ -30,11 +40,24 @@ class TestCli < MiniTest::Unit::TestCase
|
|
30
40
|
assert_equal ['foo'], Sidekiq.options[:queues]
|
31
41
|
end
|
32
42
|
|
43
|
+
it 'changes timeout' do
|
44
|
+
@cli.parse(['sidekiq', '-t', '30', '-r', './test/fake_env.rb'])
|
45
|
+
assert_equal 30, Sidekiq.options[:timeout]
|
46
|
+
end
|
47
|
+
|
33
48
|
it 'handles weights' do
|
34
49
|
@cli.parse(['sidekiq', '-q', 'foo,3', '-q', 'bar', '-r', './test/fake_env.rb'])
|
35
50
|
assert_equal %w(bar foo foo foo), Sidekiq.options[:queues].sort
|
36
51
|
end
|
37
52
|
|
53
|
+
it 'sets verbose' do
|
54
|
+
old = Sidekiq::Util.logger.level
|
55
|
+
@cli.parse(['sidekiq', '-v', '-r', './test/fake_env.rb'])
|
56
|
+
assert_equal Logger::DEBUG, Sidekiq::Util.logger.level
|
57
|
+
# If we leave the logger at DEBUG it'll add a lot of noise to the test output
|
58
|
+
Sidekiq::Util.logger.level = old
|
59
|
+
end
|
60
|
+
|
38
61
|
describe 'with pidfile' do
|
39
62
|
before do
|
40
63
|
@tmp_file = Tempfile.new('sidekiq-test')
|
@@ -140,17 +163,6 @@ class TestCli < MiniTest::Unit::TestCase
|
|
140
163
|
assert_equal 3, Sidekiq.options[:queues].select{ |q| q == 'seldom' }.length
|
141
164
|
end
|
142
165
|
end
|
143
|
-
|
144
|
-
def new_cli
|
145
|
-
cli = Sidekiq::CLI.new
|
146
|
-
def cli.die(code)
|
147
|
-
@code = code
|
148
|
-
end
|
149
|
-
|
150
|
-
def cli.valid?
|
151
|
-
!@code
|
152
|
-
end
|
153
|
-
cli
|
154
|
-
end
|
155
166
|
end
|
167
|
+
|
156
168
|
end
|
data/test/test_client.rb
CHANGED
@@ -5,7 +5,7 @@ require 'sidekiq/worker'
|
|
5
5
|
class TestClient < MiniTest::Unit::TestCase
|
6
6
|
describe 'with real redis' do
|
7
7
|
before do
|
8
|
-
Sidekiq.redis =
|
8
|
+
Sidekiq.redis = REDIS
|
9
9
|
Sidekiq.redis.flushdb
|
10
10
|
end
|
11
11
|
|
@@ -13,7 +13,6 @@ class TestClient < MiniTest::Unit::TestCase
|
|
13
13
|
Sidekiq.client_middleware.entries.clear
|
14
14
|
Sidekiq.client_middleware do |chain|
|
15
15
|
chain.add Sidekiq::Middleware::Client::UniqueJobs
|
16
|
-
chain.add Sidekiq::Middleware::Client::ResqueWebCompatibility
|
17
16
|
end
|
18
17
|
10.times { Sidekiq::Client.push('customqueue', 'class' => 'Foo', 'args' => [1, 2]) }
|
19
18
|
assert_equal 1, Sidekiq.redis.llen("queue:customqueue")
|
@@ -39,6 +38,7 @@ class TestClient < MiniTest::Unit::TestCase
|
|
39
38
|
def @redis.setex(*); nil; end
|
40
39
|
def @redis.expire(*); true; end
|
41
40
|
def @redis.with_connection; yield self; end
|
41
|
+
def @redis.with; yield self; end
|
42
42
|
Sidekiq.instance_variable_set(:@redis, @redis)
|
43
43
|
end
|
44
44
|
|
data/test/test_extensions.rb
CHANGED
@@ -5,13 +5,13 @@ require 'action_mailer'
|
|
5
5
|
require 'sidekiq/extensions/action_mailer'
|
6
6
|
require 'sidekiq/extensions/active_record'
|
7
7
|
|
8
|
+
Sidekiq.hook_rails!
|
8
9
|
|
9
10
|
class TestExtensions < MiniTest::Unit::TestCase
|
10
11
|
describe 'sidekiq extensions' do
|
11
12
|
before do
|
12
|
-
Sidekiq.
|
13
|
-
Sidekiq.
|
14
|
-
@redis = Sidekiq.redis
|
13
|
+
Sidekiq.redis = REDIS
|
14
|
+
Sidekiq.redis.flushdb
|
15
15
|
end
|
16
16
|
|
17
17
|
class MyModel < ActiveRecord::Base
|
@@ -21,9 +21,11 @@ class TestExtensions < MiniTest::Unit::TestCase
|
|
21
21
|
end
|
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
26
|
MyModel.delay.long_class_method
|
26
|
-
|
27
|
+
assert_equal ['default'], Sidekiq::Client.registered_queues
|
28
|
+
assert_equal 1, Sidekiq.redis.llen('queue:default')
|
27
29
|
end
|
28
30
|
|
29
31
|
it 'allows delayed exection of ActiveRecord instance methods' do
|
@@ -37,9 +39,11 @@ class TestExtensions < MiniTest::Unit::TestCase
|
|
37
39
|
end
|
38
40
|
|
39
41
|
it 'allows delayed delivery of ActionMailer mails' do
|
40
|
-
|
42
|
+
assert_equal [], Sidekiq::Client.registered_queues
|
43
|
+
assert_equal 0, Sidekiq.redis.llen('queue:default')
|
41
44
|
UserMailer.delay.greetings(1, 2)
|
42
|
-
|
45
|
+
assert_equal ['default'], Sidekiq::Client.registered_queues
|
46
|
+
assert_equal 1, Sidekiq.redis.llen('queue:default')
|
43
47
|
end
|
44
48
|
|
45
49
|
end
|