kulesa-sidekiq 1.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +6 -0
- data/.rvmrc +4 -0
- data/COMM-LICENSE +83 -0
- data/Changes.md +207 -0
- data/Gemfile +12 -0
- data/LICENSE +22 -0
- data/README.md +61 -0
- data/Rakefile +9 -0
- data/bin/client +7 -0
- data/bin/sidekiq +14 -0
- data/bin/sidekiqctl +74 -0
- data/config.ru +18 -0
- data/examples/chef/cookbooks/sidekiq/README.rdoc +11 -0
- data/examples/chef/cookbooks/sidekiq/recipes/default.rb +55 -0
- data/examples/chef/cookbooks/sidekiq/templates/default/monitrc.conf.erb +8 -0
- data/examples/chef/cookbooks/sidekiq/templates/default/sidekiq.erb +219 -0
- data/examples/chef/cookbooks/sidekiq/templates/default/sidekiq.yml.erb +22 -0
- data/examples/clockwork.rb +44 -0
- data/examples/config.yml +10 -0
- data/examples/monitrc.conf +6 -0
- data/examples/por.rb +27 -0
- data/examples/scheduling.rb +37 -0
- data/examples/sinkiq.rb +59 -0
- data/examples/web-ui.png +0 -0
- data/lib/sidekiq.rb +98 -0
- data/lib/sidekiq/capistrano.rb +35 -0
- data/lib/sidekiq/cli.rb +214 -0
- data/lib/sidekiq/client.rb +72 -0
- data/lib/sidekiq/extensions/action_mailer.rb +26 -0
- data/lib/sidekiq/extensions/active_record.rb +27 -0
- data/lib/sidekiq/extensions/generic_proxy.rb +21 -0
- data/lib/sidekiq/fetch.rb +76 -0
- data/lib/sidekiq/logging.rb +46 -0
- data/lib/sidekiq/manager.rb +163 -0
- data/lib/sidekiq/middleware/chain.rb +96 -0
- data/lib/sidekiq/middleware/client/unique_jobs.rb +36 -0
- data/lib/sidekiq/middleware/server/active_record.rb +13 -0
- data/lib/sidekiq/middleware/server/exception_handler.rb +38 -0
- data/lib/sidekiq/middleware/server/failure_jobs.rb +25 -0
- data/lib/sidekiq/middleware/server/logging.rb +31 -0
- data/lib/sidekiq/middleware/server/retry_jobs.rb +69 -0
- data/lib/sidekiq/middleware/server/timeout.rb +21 -0
- data/lib/sidekiq/middleware/server/unique_jobs.rb +17 -0
- data/lib/sidekiq/processor.rb +92 -0
- data/lib/sidekiq/rails.rb +21 -0
- data/lib/sidekiq/redis_connection.rb +27 -0
- data/lib/sidekiq/retry.rb +59 -0
- data/lib/sidekiq/testing.rb +44 -0
- data/lib/sidekiq/testing/inline.rb +37 -0
- data/lib/sidekiq/util.rb +40 -0
- data/lib/sidekiq/version.rb +3 -0
- data/lib/sidekiq/web.rb +185 -0
- data/lib/sidekiq/worker.rb +62 -0
- data/lib/sidekiq/yaml_patch.rb +21 -0
- data/myapp/.gitignore +15 -0
- data/myapp/Capfile +5 -0
- data/myapp/Gemfile +19 -0
- data/myapp/Rakefile +7 -0
- data/myapp/app/controllers/application_controller.rb +3 -0
- data/myapp/app/controllers/work_controller.rb +38 -0
- data/myapp/app/helpers/application_helper.rb +2 -0
- data/myapp/app/mailers/.gitkeep +0 -0
- data/myapp/app/mailers/user_mailer.rb +9 -0
- data/myapp/app/models/.gitkeep +0 -0
- data/myapp/app/models/post.rb +5 -0
- data/myapp/app/views/layouts/application.html.erb +14 -0
- data/myapp/app/views/user_mailer/greetings.html.erb +3 -0
- data/myapp/app/views/work/index.html.erb +1 -0
- data/myapp/app/workers/hard_worker.rb +10 -0
- data/myapp/config.ru +4 -0
- data/myapp/config/application.rb +59 -0
- data/myapp/config/boot.rb +6 -0
- data/myapp/config/database.yml +25 -0
- data/myapp/config/deploy.rb +15 -0
- data/myapp/config/environment.rb +5 -0
- data/myapp/config/environments/development.rb +38 -0
- data/myapp/config/environments/production.rb +67 -0
- data/myapp/config/environments/test.rb +37 -0
- data/myapp/config/initializers/backtrace_silencers.rb +7 -0
- data/myapp/config/initializers/inflections.rb +15 -0
- data/myapp/config/initializers/mime_types.rb +5 -0
- data/myapp/config/initializers/secret_token.rb +7 -0
- data/myapp/config/initializers/session_store.rb +8 -0
- data/myapp/config/initializers/sidekiq.rb +6 -0
- data/myapp/config/initializers/wrap_parameters.rb +14 -0
- data/myapp/config/locales/en.yml +5 -0
- data/myapp/config/routes.rb +10 -0
- data/myapp/db/migrate/20120123214055_create_posts.rb +10 -0
- data/myapp/db/seeds.rb +7 -0
- data/myapp/lib/assets/.gitkeep +0 -0
- data/myapp/lib/tasks/.gitkeep +0 -0
- data/myapp/log/.gitkeep +0 -0
- data/myapp/script/rails +6 -0
- data/sidekiq.gemspec +27 -0
- data/test/config.yml +9 -0
- data/test/fake_env.rb +0 -0
- data/test/helper.rb +16 -0
- data/test/test_cli.rb +168 -0
- data/test/test_client.rb +119 -0
- data/test/test_extensions.rb +69 -0
- data/test/test_manager.rb +51 -0
- data/test/test_middleware.rb +92 -0
- data/test/test_processor.rb +32 -0
- data/test/test_retry.rb +125 -0
- data/test/test_stats.rb +68 -0
- data/test/test_testing.rb +97 -0
- data/test/test_testing_inline.rb +75 -0
- data/test/test_web.rb +122 -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 +20 -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/javascripts/vendor/jquery.timeago.js +148 -0
- data/web/assets/stylesheets/application.css +27 -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 +48 -0
- data/web/views/layout.slim +26 -0
- data/web/views/queue.slim +11 -0
- data/web/views/retries.slim +29 -0
- data/web/views/retry.slim +52 -0
- metadata +371 -0
data/examples/sinkiq.rb
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Make sure you have Sinatra installed, then start sidekiq with
|
|
2
|
+
# ./bin/sidekiq -r ./examples/sinkiq.rb
|
|
3
|
+
# Simply run Sinatra with
|
|
4
|
+
# ruby examples/sinkiq.rb
|
|
5
|
+
# and then browse to http://localhost:4567
|
|
6
|
+
#
|
|
7
|
+
require 'sinatra'
|
|
8
|
+
require 'sidekiq'
|
|
9
|
+
require 'redis'
|
|
10
|
+
|
|
11
|
+
$redis = Redis.connect
|
|
12
|
+
|
|
13
|
+
class SinatraWorker
|
|
14
|
+
include Sidekiq::Worker
|
|
15
|
+
|
|
16
|
+
def perform(msg="lulz you forgot a msg!")
|
|
17
|
+
$redis.lpush("sinkiq-example-messages", msg)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
get '/' do
|
|
22
|
+
@failed = $redis.get('stat:failed')
|
|
23
|
+
@processed = $redis.get('stat:processed')
|
|
24
|
+
@messages = $redis.lrange('sinkiq-example-messages', 0, -1)
|
|
25
|
+
erb :index
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
post '/msg' do
|
|
29
|
+
SinatraWorker.perform_async params[:msg]
|
|
30
|
+
redirect to('/')
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
__END__
|
|
34
|
+
|
|
35
|
+
@@ layout
|
|
36
|
+
<html>
|
|
37
|
+
<head>
|
|
38
|
+
<title>Sinatra + Sidekiq</title>
|
|
39
|
+
<body>
|
|
40
|
+
<%= yield %>
|
|
41
|
+
</body>
|
|
42
|
+
</html>
|
|
43
|
+
|
|
44
|
+
@@ index
|
|
45
|
+
<h1>Sinatra + Sidekiq Example</h1>
|
|
46
|
+
<h2>Failed: <%= @failed %></h2>
|
|
47
|
+
<h2>Processed: <%= @processed %></h2>
|
|
48
|
+
|
|
49
|
+
<form method="post" action="/msg">
|
|
50
|
+
<input type="text" name="msg">
|
|
51
|
+
<input type="submit" value="Add Message">
|
|
52
|
+
</form>
|
|
53
|
+
|
|
54
|
+
<a href="/">Refresh page</a>
|
|
55
|
+
|
|
56
|
+
<h3>Messages</h3>
|
|
57
|
+
<% @messages.each do |msg| %>
|
|
58
|
+
<p><%= msg %></p>
|
|
59
|
+
<% end %>
|
data/examples/web-ui.png
ADDED
|
Binary file
|
data/lib/sidekiq.rb
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
require 'sidekiq/version'
|
|
2
|
+
require 'sidekiq/logging'
|
|
3
|
+
require 'sidekiq/client'
|
|
4
|
+
require 'sidekiq/worker'
|
|
5
|
+
require 'sidekiq/redis_connection'
|
|
6
|
+
require 'sidekiq/util'
|
|
7
|
+
|
|
8
|
+
require 'sidekiq/extensions/action_mailer'
|
|
9
|
+
require 'sidekiq/extensions/active_record'
|
|
10
|
+
require 'sidekiq/rails' if defined?(::Rails)
|
|
11
|
+
|
|
12
|
+
module Sidekiq
|
|
13
|
+
|
|
14
|
+
DEFAULTS = {
|
|
15
|
+
:queues => [],
|
|
16
|
+
:concurrency => 25,
|
|
17
|
+
:require => '.',
|
|
18
|
+
:environment => nil,
|
|
19
|
+
:timeout => 8,
|
|
20
|
+
:enable_rails_extensions => true,
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
def self.options
|
|
24
|
+
@options ||= DEFAULTS.dup
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def self.options=(opts)
|
|
28
|
+
@options = opts
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
##
|
|
32
|
+
# Configuration for Sidekiq server, use like:
|
|
33
|
+
#
|
|
34
|
+
# Sidekiq.configure_server do |config|
|
|
35
|
+
# config.redis = { :namespace => 'myapp', :size => 25, :url => 'redis://myhost:8877/mydb' }
|
|
36
|
+
# config.server_middleware do |chain|
|
|
37
|
+
# chain.add MyServerHook
|
|
38
|
+
# end
|
|
39
|
+
# end
|
|
40
|
+
def self.configure_server
|
|
41
|
+
yield self if server?
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
##
|
|
45
|
+
# Configuration for Sidekiq client, use like:
|
|
46
|
+
#
|
|
47
|
+
# Sidekiq.configure_client do |config|
|
|
48
|
+
# config.redis = { :namespace => 'myapp', :size => 1, :url => 'redis://myhost:8877/mydb' }
|
|
49
|
+
# end
|
|
50
|
+
def self.configure_client
|
|
51
|
+
yield self unless server?
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def self.server?
|
|
55
|
+
defined?(Sidekiq::CLI)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def self.redis(&block)
|
|
59
|
+
@redis ||= Sidekiq::RedisConnection.create
|
|
60
|
+
raise ArgumentError, "requires a block" if !block
|
|
61
|
+
@redis.with(&block)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def self.redis=(hash)
|
|
65
|
+
if hash.is_a?(Hash)
|
|
66
|
+
@redis = RedisConnection.create(hash)
|
|
67
|
+
elsif hash.is_a?(ConnectionPool)
|
|
68
|
+
@redis = hash
|
|
69
|
+
else
|
|
70
|
+
raise ArgumentError, "redis= requires a Hash or ConnectionPool"
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def self.client_middleware
|
|
75
|
+
@client_chain ||= Client.default_middleware
|
|
76
|
+
yield @client_chain if block_given?
|
|
77
|
+
@client_chain
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def self.server_middleware
|
|
81
|
+
@server_chain ||= Processor.default_middleware
|
|
82
|
+
yield @server_chain if block_given?
|
|
83
|
+
@server_chain
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def self.load_json(string)
|
|
87
|
+
MultiJson.decode(string)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def self.dump_json(object)
|
|
91
|
+
MultiJson.encode(object)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def self.logger
|
|
95
|
+
Sidekiq::Logging.logger
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
Capistrano::Configuration.instance.load do
|
|
2
|
+
before "deploy", "sidekiq:quiet"
|
|
3
|
+
after "deploy:stop", "sidekiq:stop"
|
|
4
|
+
after "deploy:start", "sidekiq:start"
|
|
5
|
+
after "deploy:restart", "sidekiq:restart"
|
|
6
|
+
|
|
7
|
+
_cset(:sidekiq_timeout) { 10 }
|
|
8
|
+
_cset(:sidekiq_role) { :app }
|
|
9
|
+
|
|
10
|
+
namespace :sidekiq do
|
|
11
|
+
|
|
12
|
+
desc "Quiet sidekiq (stop accepting new work)"
|
|
13
|
+
task :quiet, :roles => lambda { fetch(:sidekiq_role) }, :on_no_matching_servers => :continue do
|
|
14
|
+
run "cd #{current_path} && if [ -f #{current_path}/tmp/pids/sidekiq.pid ]; then #{fetch(:bundle_cmd, "bundle")} exec sidekiqctl quiet #{current_path}/tmp/pids/sidekiq.pid ; fi"
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
desc "Stop sidekiq"
|
|
18
|
+
task :stop, :roles => lambda { fetch(:sidekiq_role) }, :on_no_matching_servers => :continue do
|
|
19
|
+
run "cd #{current_path} && if [ -f #{current_path}/tmp/pids/sidekiq.pid ]; then #{fetch(:bundle_cmd, "bundle")} exec sidekiqctl stop #{current_path}/tmp/pids/sidekiq.pid #{fetch :sidekiq_timeout} ; fi"
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
desc "Start sidekiq"
|
|
23
|
+
task :start, :roles => lambda { fetch(:sidekiq_role) }, :on_no_matching_servers => :continue do
|
|
24
|
+
rails_env = fetch(:rails_env, "production")
|
|
25
|
+
run "cd #{current_path} ; nohup #{fetch(:bundle_cmd, "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 &", :pty => false
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
desc "Restart sidekiq"
|
|
29
|
+
task :restart, :roles => lambda { fetch(:sidekiq_role) }, :on_no_matching_servers => :continue do
|
|
30
|
+
stop
|
|
31
|
+
start
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
end
|
|
35
|
+
end
|
data/lib/sidekiq/cli.rb
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
trap 'INT' do
|
|
2
|
+
# Handle Ctrl-C in JRuby like MRI
|
|
3
|
+
# http://jira.codehaus.org/browse/JRUBY-4637
|
|
4
|
+
Sidekiq::CLI.instance.interrupt
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
trap 'TERM' do
|
|
8
|
+
# Heroku sends TERM and then waits 10 seconds for process to exit.
|
|
9
|
+
Sidekiq::CLI.instance.interrupt
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
trap 'USR1' do
|
|
13
|
+
Sidekiq.logger.info "Received USR1, no longer accepting new work"
|
|
14
|
+
mgr = Sidekiq::CLI.instance.manager
|
|
15
|
+
mgr.stop! if mgr
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
trap 'TTIN' do
|
|
19
|
+
Thread.list.each do |thread|
|
|
20
|
+
puts "Thread TID-#{thread.object_id.to_s(36)} #{thread['label']}"
|
|
21
|
+
puts thread.backtrace.join("\n")
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
require 'yaml'
|
|
26
|
+
require 'singleton'
|
|
27
|
+
require 'optparse'
|
|
28
|
+
require 'celluloid'
|
|
29
|
+
|
|
30
|
+
require 'sidekiq'
|
|
31
|
+
require 'sidekiq/util'
|
|
32
|
+
require 'sidekiq/manager'
|
|
33
|
+
require 'sidekiq/retry'
|
|
34
|
+
|
|
35
|
+
module Sidekiq
|
|
36
|
+
class CLI
|
|
37
|
+
include Util
|
|
38
|
+
include Singleton
|
|
39
|
+
|
|
40
|
+
# Used for CLI testing
|
|
41
|
+
attr_accessor :code
|
|
42
|
+
attr_accessor :manager
|
|
43
|
+
|
|
44
|
+
def initialize
|
|
45
|
+
@code = nil
|
|
46
|
+
@interrupt_mutex = Mutex.new
|
|
47
|
+
@interrupted = false
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def parse(args=ARGV)
|
|
51
|
+
@code = nil
|
|
52
|
+
Sidekiq.logger
|
|
53
|
+
|
|
54
|
+
cli = parse_options(args)
|
|
55
|
+
config = parse_config(cli)
|
|
56
|
+
options.merge!(config.merge(cli))
|
|
57
|
+
|
|
58
|
+
Sidekiq.logger.level = Logger::DEBUG if options[:verbose]
|
|
59
|
+
Celluloid.logger = nil
|
|
60
|
+
|
|
61
|
+
validate!
|
|
62
|
+
write_pid
|
|
63
|
+
boot_system
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def run
|
|
67
|
+
@manager = Sidekiq::Manager.new(options)
|
|
68
|
+
poller = Sidekiq::Retry::Poller.new
|
|
69
|
+
begin
|
|
70
|
+
logger.info 'Starting processing, hit Ctrl-C to stop'
|
|
71
|
+
@manager.start!
|
|
72
|
+
poller.poll!
|
|
73
|
+
sleep
|
|
74
|
+
rescue Interrupt
|
|
75
|
+
logger.info 'Shutting down'
|
|
76
|
+
poller.terminate! if poller.alive?
|
|
77
|
+
@manager.stop!(:shutdown => true, :timeout => options[:timeout])
|
|
78
|
+
@manager.wait(:shutdown)
|
|
79
|
+
# Explicitly exit so busy Processor threads can't block
|
|
80
|
+
# process shutdown.
|
|
81
|
+
exit(0)
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def interrupt
|
|
86
|
+
@interrupt_mutex.synchronize do
|
|
87
|
+
unless @interrupted
|
|
88
|
+
@interrupted = true
|
|
89
|
+
Thread.main.raise Interrupt
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
private
|
|
95
|
+
|
|
96
|
+
def die(code)
|
|
97
|
+
exit(code)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def options
|
|
101
|
+
Sidekiq.options
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def detected_environment
|
|
105
|
+
options[:environment] ||= ENV['RAILS_ENV'] || ENV['RACK_ENV'] || 'development'
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def boot_system
|
|
109
|
+
ENV['RACK_ENV'] = ENV['RAILS_ENV'] = detected_environment
|
|
110
|
+
|
|
111
|
+
raise ArgumentError, "#{options[:require]} does not exist" unless File.exist?(options[:require])
|
|
112
|
+
|
|
113
|
+
if File.directory?(options[:require])
|
|
114
|
+
require 'rails'
|
|
115
|
+
require 'sidekiq/rails'
|
|
116
|
+
require File.expand_path("#{options[:require]}/config/environment.rb")
|
|
117
|
+
::Rails.application.eager_load!
|
|
118
|
+
else
|
|
119
|
+
require options[:require]
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def validate!
|
|
124
|
+
options[:queues] << 'default' if options[:queues].empty?
|
|
125
|
+
options[:queues].shuffle!
|
|
126
|
+
|
|
127
|
+
if !File.exist?(options[:require]) ||
|
|
128
|
+
(File.directory?(options[:require]) && !File.exist?("#{options[:require]}/config/application.rb"))
|
|
129
|
+
logger.info "=================================================================="
|
|
130
|
+
logger.info " Please point sidekiq to a Rails 3 application or a Ruby file "
|
|
131
|
+
logger.info " to load your worker classes with -r [DIR|FILE]."
|
|
132
|
+
logger.info "=================================================================="
|
|
133
|
+
logger.info @parser
|
|
134
|
+
die(1)
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def parse_options(argv)
|
|
139
|
+
opts = {}
|
|
140
|
+
|
|
141
|
+
@parser = OptionParser.new do |o|
|
|
142
|
+
o.on "-q", "--queue QUEUE,WEIGHT", "Queue to process, with optional weight" do |arg|
|
|
143
|
+
q, weight = arg.split(",")
|
|
144
|
+
parse_queues(opts, q, weight)
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
o.on "-v", "--verbose", "Print more verbose output" do
|
|
148
|
+
Sidekiq.logger.level = ::Logger::DEBUG
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
o.on '-e', '--environment ENV', "Application environment" do |arg|
|
|
152
|
+
opts[:environment] = arg
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
o.on '-t', '--timeout NUM', "Shutdown timeout" do |arg|
|
|
156
|
+
opts[:timeout] = arg.to_i
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
o.on '-r', '--require [PATH|DIR]', "Location of Rails application with workers or file to require" do |arg|
|
|
160
|
+
opts[:require] = arg
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
o.on '-c', '--concurrency INT', "processor threads to use" do |arg|
|
|
164
|
+
opts[:concurrency] = arg.to_i
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
o.on '-P', '--pidfile PATH', "path to pidfile" do |arg|
|
|
168
|
+
opts[:pidfile] = arg
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
o.on '-C', '--config PATH', "path to YAML config file" do |arg|
|
|
172
|
+
opts[:config_file] = arg
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
o.on '-V', '--version', "Print version and exit" do |arg|
|
|
176
|
+
puts "Sidekiq #{Sidekiq::VERSION}"
|
|
177
|
+
die(0)
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
@parser.banner = "sidekiq [options]"
|
|
182
|
+
@parser.on_tail "-h", "--help", "Show help" do
|
|
183
|
+
logger.info @parser
|
|
184
|
+
die 1
|
|
185
|
+
end
|
|
186
|
+
@parser.parse!(argv)
|
|
187
|
+
opts
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
def write_pid
|
|
191
|
+
if path = options[:pidfile]
|
|
192
|
+
File.open(path, 'w') do |f|
|
|
193
|
+
f.puts Process.pid
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
def parse_config(cli)
|
|
199
|
+
opts = {}
|
|
200
|
+
if cli[:config_file] && File.exist?(cli[:config_file])
|
|
201
|
+
opts = YAML.load_file cli[:config_file]
|
|
202
|
+
queues = opts.delete(:queues) || []
|
|
203
|
+
queues.each { |name, weight| parse_queues(opts, name, weight) }
|
|
204
|
+
end
|
|
205
|
+
opts
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
def parse_queues(opts, q, weight)
|
|
209
|
+
(weight || 1).to_i.times do
|
|
210
|
+
(opts[:queues] ||= []) << q
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
end
|
|
214
|
+
end
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
require 'multi_json'
|
|
2
|
+
|
|
3
|
+
require 'sidekiq/middleware/chain'
|
|
4
|
+
require 'sidekiq/middleware/client/unique_jobs'
|
|
5
|
+
|
|
6
|
+
module Sidekiq
|
|
7
|
+
class Client
|
|
8
|
+
|
|
9
|
+
def self.default_middleware
|
|
10
|
+
Middleware::Chain.new do |m|
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def self.registered_workers
|
|
15
|
+
Sidekiq.redis { |x| x.smembers('workers') }
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def self.registered_queues
|
|
19
|
+
Sidekiq.redis { |x| x.smembers('queues') }
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
##
|
|
23
|
+
# The main method used to push a job to Redis. Accepts a number of options:
|
|
24
|
+
#
|
|
25
|
+
# queue - the named queue to use, default 'default'
|
|
26
|
+
# class - the worker class to call, required
|
|
27
|
+
# args - an array of simple arguments to the perform method, must be JSON-serializable
|
|
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
|
|
30
|
+
#
|
|
31
|
+
# All options must be strings, not symbols. NB: because we are serializing to JSON, all
|
|
32
|
+
# symbols in 'args' will be converted to strings.
|
|
33
|
+
#
|
|
34
|
+
# Example:
|
|
35
|
+
# Sidekiq::Client.push('queue' => 'my_queue', 'class' => MyWorker, 'args' => ['foo', 1, :bat => 'bar'])
|
|
36
|
+
#
|
|
37
|
+
def self.push(item)
|
|
38
|
+
raise(ArgumentError, "Message must be a Hash of the form: { 'class' => SomeWorker, 'args' => ['bob', 1, :foo => 'bar'] }") unless item.is_a?(Hash)
|
|
39
|
+
raise(ArgumentError, "Message must include a class and set of arguments: #{item.inspect}") if !item['class'] || !item['args']
|
|
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')
|
|
41
|
+
|
|
42
|
+
worker_class = item['class']
|
|
43
|
+
item['class'] = item['class'].to_s
|
|
44
|
+
|
|
45
|
+
item = worker_class.get_sidekiq_options.merge(item)
|
|
46
|
+
item['retry'] = !!item['retry']
|
|
47
|
+
queue = item['queue']
|
|
48
|
+
|
|
49
|
+
pushed = false
|
|
50
|
+
Sidekiq.client_middleware.invoke(worker_class, item, queue) do
|
|
51
|
+
payload = Sidekiq.dump_json(item)
|
|
52
|
+
Sidekiq.redis do |conn|
|
|
53
|
+
_, pushed = conn.multi do
|
|
54
|
+
conn.sadd('queues', queue)
|
|
55
|
+
conn.rpush("queue:#{queue}", payload)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
!! pushed
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Redis compatibility helper. Example usage:
|
|
63
|
+
#
|
|
64
|
+
# Sidekiq::Client.enqueue(MyWorker, 'foo', 1, :bat => 'bar')
|
|
65
|
+
#
|
|
66
|
+
# Messages are enqueued to the 'default' queue.
|
|
67
|
+
#
|
|
68
|
+
def self.enqueue(klass, *args)
|
|
69
|
+
klass.perform_async(*args)
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|