sidekiq 0.5.1 → 0.6.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/.gitignore +5 -0
- data/.rvmrc +2 -1
- data/Changes.md +11 -0
- data/LICENSE +11 -4
- data/README.md +1 -7
- data/TODO.md +0 -1
- data/bin/sidekiq +2 -0
- data/examples/por.rb +17 -0
- data/examples/sinkiq.rb +57 -0
- data/lib/sidekiq.rb +1 -1
- data/lib/sidekiq/cli.rb +72 -34
- data/lib/sidekiq/client.rb +33 -16
- data/lib/sidekiq/manager.rb +37 -47
- data/lib/sidekiq/middleware/chain.rb +92 -0
- data/lib/sidekiq/middleware/client/resque_web_compatibility.rb +17 -0
- data/lib/sidekiq/middleware/client/unique_jobs.rb +30 -0
- data/lib/sidekiq/middleware/server/active_record.rb +13 -0
- data/lib/sidekiq/middleware/server/airbrake.rb +30 -0
- data/lib/sidekiq/middleware/server/unique_jobs.rb +17 -0
- data/lib/sidekiq/processor.rb +74 -16
- data/lib/sidekiq/redis_connection.rb +23 -0
- data/lib/sidekiq/testing.rb +34 -0
- data/lib/sidekiq/util.rb +21 -12
- data/lib/sidekiq/version.rb +1 -1
- data/lib/sidekiq/worker.rb +6 -7
- data/myapp/Gemfile +4 -1
- data/myapp/Gemfile.lock +29 -6
- data/myapp/app/controllers/work_controller.rb +9 -0
- data/myapp/app/views/work/index.html.erb +1 -0
- data/myapp/app/workers/hard_worker.rb +4 -2
- data/myapp/config/environments/development.rb +1 -0
- data/myapp/config/initializers/sidekiq.rb +1 -0
- data/myapp/config/routes.rb +4 -56
- data/sidekiq.gemspec +1 -0
- data/test/fake_env.rb +0 -0
- data/test/helper.rb +3 -0
- data/test/test_cli.rb +49 -0
- data/test/test_client.rb +52 -10
- data/test/test_manager.rb +11 -6
- data/test/test_middleware.rb +39 -20
- data/test/test_processor.rb +3 -2
- data/test/test_stats.rb +79 -0
- data/test/test_testing.rb +32 -0
- metadata +47 -18
- data/Gemfile.lock +0 -32
- data/lib/sidekiq/middleware.rb +0 -89
- data/test/timed_queue.rb +0 -42
data/.rvmrc
CHANGED
data/Changes.md
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
0.6.0
|
2
|
+
-----------
|
3
|
+
|
4
|
+
- Resque-compatible processing stats in redis (mperham)
|
5
|
+
- Simple client testing support in sidekiq/testing (mperham)
|
6
|
+
- Plain old Ruby support via the -r cli flag (mperham)
|
7
|
+
- Refactored middleware support, introducing ability to add client-side middleware (ryanlecompte)
|
8
|
+
- Added middleware for ignoring duplicate jobs (ryanlecompte)
|
9
|
+
- Added middleware for displaying jobs in resque-web dashboard (maxjustus)
|
10
|
+
- Added redis namespacing support (maxjustus)
|
11
|
+
|
1
12
|
0.5.1
|
2
13
|
-----------
|
3
14
|
|
data/LICENSE
CHANGED
@@ -1,9 +1,16 @@
|
|
1
1
|
Copyright (c) Mike Perham
|
2
2
|
|
3
|
-
|
3
|
+
You may choose to license Sidekiq in one of two ways:
|
4
|
+
|
5
|
+
- Open Source under the GPLv3
|
4
6
|
|
5
7
|
Please see <http://www.gnu.org/licenses/gpl-3.0.html> for license text.
|
6
8
|
|
7
|
-
|
8
|
-
|
9
|
-
|
9
|
+
- Commercial License
|
10
|
+
|
11
|
+
The Sencha commercial software license in COMM-LICENSE. You must pledge
|
12
|
+
$50 to my Pledgie fund at http://www.pledgie.com/campaigns/16623 to use
|
13
|
+
this license.
|
14
|
+
|
15
|
+
This commercial license is just meant to help support my OSS work. If
|
16
|
+
you do buy the commercial licensing option, thank you for your support!
|
data/README.md
CHANGED
@@ -47,13 +47,7 @@ Please see the [sidekiq wiki](https://github.com/mperham/sidekiq/wiki) for more
|
|
47
47
|
License
|
48
48
|
-----------------
|
49
49
|
|
50
|
-
|
51
|
-
license, you must give $50 to my [Pledgie campaign](http://www.pledgie.com/campaigns/16623).
|
52
|
-
Considering the hundreds of hours I've spent writing OSS, I hope you
|
53
|
-
think this is a reasonable price. BTW, the commercial license is in
|
54
|
-
COMM-LICENSE and is the [Sencha commercial license v1.10](http://www.sencha.com/legal/sencha-commercial-software-license-agreement/) with the Support (section 11) terms removed.
|
55
|
-
Support is provided through GitHub Issues. You are welcome to try the
|
56
|
-
software for 2 weeks.
|
50
|
+
Please see LICENSE for licensing details.
|
57
51
|
|
58
52
|
<a href='http://www.pledgie.com/campaigns/16623'><img alt='Click here to lend your support to Open Source and make a donation at www.pledgie.com !' src='http://www.pledgie.com/campaigns/16623.png?skin_name=chrome' border='0' /></a>
|
59
53
|
|
data/TODO.md
CHANGED
data/bin/sidekiq
CHANGED
data/examples/por.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'sidekiq'
|
2
|
+
|
3
|
+
# Start up sidekiq via
|
4
|
+
# ./bin/sidekiq -r ./examples/por.rb
|
5
|
+
# and then you can open up an IRB session like so:
|
6
|
+
# irb -r ./examples/por.rb
|
7
|
+
# where you can then say
|
8
|
+
# PlainOldRuby.perform_async "like a dog", 3
|
9
|
+
#
|
10
|
+
class PlainOldRuby
|
11
|
+
include Sidekiq::Worker
|
12
|
+
|
13
|
+
def perform(how_hard="super hard", how_long=1)
|
14
|
+
sleep how_long
|
15
|
+
puts "Workin' #{how_hard}"
|
16
|
+
end
|
17
|
+
end
|
data/examples/sinkiq.rb
ADDED
@@ -0,0 +1,57 @@
|
|
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/worker'
|
9
|
+
$redis = Sidekiq::RedisConnection.create
|
10
|
+
|
11
|
+
class SinatraWorker
|
12
|
+
include Sidekiq::Worker
|
13
|
+
|
14
|
+
def perform(msg="lulz you forgot a msg!")
|
15
|
+
$redis.lpush("sinkiq-example-messages", msg)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
get '/' do
|
20
|
+
@failed = $redis.get('stat:failed')
|
21
|
+
@processed = $redis.get('stat:processed')
|
22
|
+
@messages = $redis.lrange('sinkiq-example-messages', 0, -1)
|
23
|
+
erb :index
|
24
|
+
end
|
25
|
+
|
26
|
+
post '/msg' do
|
27
|
+
SinatraWorker.perform_async params[:msg]
|
28
|
+
redirect to('/')
|
29
|
+
end
|
30
|
+
|
31
|
+
__END__
|
32
|
+
|
33
|
+
@@ layout
|
34
|
+
<html>
|
35
|
+
<head>
|
36
|
+
<title>Sinatra + Sidekiq</title>
|
37
|
+
<body>
|
38
|
+
<%= yield %>
|
39
|
+
</body>
|
40
|
+
</html>
|
41
|
+
|
42
|
+
@@ index
|
43
|
+
<h1>Sinata + Sidekiq Example</h1>
|
44
|
+
<h2>Failed: <%= @failed %></h2>
|
45
|
+
<h2>Processed: <%= @processed %></h2>
|
46
|
+
|
47
|
+
<form method="post" action="/msg">
|
48
|
+
<input type="text" name="msg">
|
49
|
+
<input type="submit" value="Add Message">
|
50
|
+
</form>
|
51
|
+
|
52
|
+
<a href="/">Refresh page</a>
|
53
|
+
|
54
|
+
<h3>Messages</h3>
|
55
|
+
<% @messages.each do |msg| %>
|
56
|
+
<p><%= msg %></p>
|
57
|
+
<% end %>
|
data/lib/sidekiq.rb
CHANGED
data/lib/sidekiq/cli.rb
CHANGED
@@ -1,34 +1,50 @@
|
|
1
|
+
trap 'INT' do
|
2
|
+
# Handle Ctrl-C in JRuby like MRI
|
3
|
+
# http://jira.codehaus.org/browse/JRUBY-4637
|
4
|
+
Thread.main.raise Interrupt
|
5
|
+
end
|
6
|
+
|
7
|
+
trap 'TERM' do
|
8
|
+
# Heroku sends TERM and then waits 10 seconds for process to exit.
|
9
|
+
Thread.main.raise Interrupt
|
10
|
+
end
|
11
|
+
|
1
12
|
require 'optparse'
|
2
13
|
require 'sidekiq/version'
|
3
14
|
require 'sidekiq/util'
|
4
|
-
require 'sidekiq/
|
15
|
+
require 'sidekiq/redis_connection'
|
5
16
|
require 'sidekiq/manager'
|
6
|
-
require 'connection_pool'
|
7
17
|
|
8
18
|
module Sidekiq
|
9
19
|
class CLI
|
10
20
|
include Util
|
11
21
|
|
22
|
+
# Used for CLI testing
|
23
|
+
attr_accessor :options, :code
|
24
|
+
|
12
25
|
def initialize
|
13
|
-
|
14
|
-
validate!
|
15
|
-
boot_rails
|
26
|
+
@code = nil
|
16
27
|
end
|
17
28
|
|
18
|
-
|
29
|
+
def parse(args=ARGV)
|
30
|
+
Sidekiq::Util.logger
|
31
|
+
parse_options(args)
|
32
|
+
validate!
|
33
|
+
boot_system
|
34
|
+
end
|
19
35
|
|
20
36
|
def run
|
21
|
-
|
22
|
-
manager = Sidekiq::Manager.new(@options
|
37
|
+
Sidekiq::Manager.redis = RedisConnection.create(:url => @options[:server], :namespace => @options[:namespace])
|
38
|
+
manager = Sidekiq::Manager.new(@options)
|
23
39
|
begin
|
24
|
-
|
40
|
+
logger.info 'Starting processing, hit Ctrl-C to stop'
|
25
41
|
manager.start!
|
26
42
|
# HACK need to determine how to pause main thread while
|
27
43
|
# waiting for signals.
|
28
|
-
sleep
|
44
|
+
sleep
|
29
45
|
rescue Interrupt
|
30
46
|
# TODO Need clean shutdown support from Celluloid
|
31
|
-
|
47
|
+
logger.info 'Shutting down, pausing 5 seconds to let workers finish...'
|
32
48
|
manager.stop!
|
33
49
|
manager.wait(:shutdown)
|
34
50
|
end
|
@@ -36,54 +52,76 @@ module Sidekiq
|
|
36
52
|
|
37
53
|
private
|
38
54
|
|
39
|
-
def
|
40
|
-
|
41
|
-
require File.expand_path("#{@options[:rails]}/config/environment.rb")
|
42
|
-
::Rails.application.eager_load!
|
55
|
+
def die(code)
|
56
|
+
exit(code)
|
43
57
|
end
|
44
58
|
|
45
|
-
def
|
46
|
-
|
59
|
+
def detected_environment
|
60
|
+
@options[:environment] || ENV['RAILS_ENV'] || ENV['RACK_ENV'] || 'development'
|
61
|
+
end
|
62
|
+
|
63
|
+
def boot_system
|
64
|
+
ENV['RACK_ENV'] = ENV['RAILS_ENV'] = detected_environment
|
65
|
+
|
66
|
+
raise ArgumentError, "#{@options[:require]} does not exist" if !File.exist?(@options[:require])
|
47
67
|
|
48
|
-
if
|
49
|
-
|
50
|
-
|
51
|
-
|
68
|
+
if File.directory?(@options[:require])
|
69
|
+
require File.expand_path("#{@options[:require]}/config/environment.rb")
|
70
|
+
::Rails.application.eager_load!
|
71
|
+
else
|
72
|
+
require @options[:require]
|
52
73
|
end
|
53
74
|
end
|
54
75
|
|
55
|
-
def
|
76
|
+
def validate!
|
77
|
+
@options[:queues] << 'default' if @options[:queues].empty?
|
78
|
+
@options[:queues].shuffle!
|
79
|
+
|
80
|
+
if !File.exist?(@options[:require]) ||
|
81
|
+
(File.directory?(@options[:require]) && !File.exist?("#{@options[:require]}/config/application.rb"))
|
82
|
+
logger.info "=================================================================="
|
83
|
+
logger.info " Please point sidekiq to a Rails 3 application or a Ruby file "
|
84
|
+
logger.info " to load your worker classes with -r [DIR|FILE]."
|
85
|
+
logger.info "=================================================================="
|
86
|
+
logger.info @parser
|
87
|
+
die(1)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def parse_options(argv)
|
56
92
|
@options = {
|
57
|
-
:
|
58
|
-
:queues => ['default'],
|
93
|
+
:queues => [],
|
59
94
|
:processor_count => 25,
|
60
|
-
:
|
61
|
-
:
|
62
|
-
:environment => 'production',
|
95
|
+
:require => '.',
|
96
|
+
:environment => nil,
|
63
97
|
}
|
64
98
|
|
65
99
|
@parser = OptionParser.new do |o|
|
66
100
|
o.on "-q", "--queue QUEUE,WEIGHT", "Queue to process, with optional weight" do |arg|
|
67
101
|
(q, weight) = arg.split(",")
|
68
|
-
(weight || 1).times do
|
102
|
+
(weight || 1).to_i.times do
|
69
103
|
@options[:queues] << q
|
70
104
|
end
|
71
105
|
end
|
72
106
|
|
73
107
|
o.on "-v", "--verbose", "Print more verbose output" do
|
74
|
-
|
108
|
+
Sidekiq::Util.logger.level = Logger::DEBUG
|
109
|
+
end
|
110
|
+
|
111
|
+
o.on "-n", "--namespace NAMESPACE", "namespace worker queues are under" do |arg|
|
112
|
+
@options[:namespace] = arg
|
75
113
|
end
|
76
114
|
|
77
115
|
o.on "-s", "--server LOCATION", "Where to find Redis" do |arg|
|
78
116
|
@options[:server] = arg
|
79
117
|
end
|
80
118
|
|
81
|
-
o.on '-e', '--environment ENV', "
|
119
|
+
o.on '-e', '--environment ENV', "Application environment" do |arg|
|
82
120
|
@options[:environment] = arg
|
83
121
|
end
|
84
122
|
|
85
|
-
o.on '-r', '--
|
86
|
-
@options[:
|
123
|
+
o.on '-r', '--require [PATH|DIR]', "Location of Rails application with workers or file to require" do |arg|
|
124
|
+
@options[:require] = arg
|
87
125
|
end
|
88
126
|
|
89
127
|
o.on '-c', '--concurrency INT', "processor threads to use" do |arg|
|
@@ -93,8 +131,8 @@ module Sidekiq
|
|
93
131
|
|
94
132
|
@parser.banner = "sidekiq [options]"
|
95
133
|
@parser.on_tail "-h", "--help", "Show help" do
|
96
|
-
|
97
|
-
|
134
|
+
logger.info @parser
|
135
|
+
die 1
|
98
136
|
end
|
99
137
|
@parser.parse!(argv)
|
100
138
|
end
|
data/lib/sidekiq/client.rb
CHANGED
@@ -1,30 +1,53 @@
|
|
1
1
|
require 'multi_json'
|
2
2
|
require 'redis'
|
3
3
|
|
4
|
+
require 'sidekiq/redis_connection'
|
5
|
+
require 'sidekiq/middleware/chain'
|
6
|
+
require 'sidekiq/middleware/client/resque_web_compatibility'
|
7
|
+
require 'sidekiq/middleware/client/unique_jobs'
|
8
|
+
|
4
9
|
module Sidekiq
|
5
10
|
class Client
|
6
11
|
|
7
|
-
def self.
|
8
|
-
@
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
12
|
+
def self.middleware
|
13
|
+
@middleware ||= begin
|
14
|
+
m = Middleware::Chain.new
|
15
|
+
m.register do
|
16
|
+
use Middleware::Client::UniqueJobs, Client.redis
|
17
|
+
use Middleware::Client::ResqueWebCompatibility, Client.redis
|
18
|
+
end
|
19
|
+
m
|
13
20
|
end
|
14
21
|
end
|
15
22
|
|
23
|
+
def self.queues
|
24
|
+
@queues ||= {}
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.redis
|
28
|
+
@redis ||= RedisConnection.create
|
29
|
+
end
|
30
|
+
|
16
31
|
def self.redis=(redis)
|
17
32
|
@redis = redis
|
18
33
|
end
|
19
34
|
|
20
35
|
# Example usage:
|
21
36
|
# Sidekiq::Client.push('my_queue', 'class' => MyWorker, 'args' => ['foo', 1, :bat => 'bar'])
|
22
|
-
def self.push(queue=
|
37
|
+
def self.push(queue=nil, item)
|
23
38
|
raise(ArgumentError, "Message must be a Hash of the form: { 'class' => SomeClass, 'args' => ['bob', 1, :foo => 'bar'] }") unless item.is_a?(Hash)
|
24
39
|
raise(ArgumentError, "Message must include a class and set of arguments: #{item.inspect}") if !item['class'] || !item['args']
|
25
40
|
|
41
|
+
queue = queue || queues[item['class'].to_s] || 'default'
|
42
|
+
|
26
43
|
item['class'] = item['class'].to_s if !item['class'].is_a?(String)
|
27
|
-
|
44
|
+
|
45
|
+
pushed = false
|
46
|
+
middleware.invoke(item, queue) do
|
47
|
+
redis.rpush("queue:#{queue}", MultiJson.encode(item))
|
48
|
+
pushed = true
|
49
|
+
end
|
50
|
+
pushed
|
28
51
|
end
|
29
52
|
|
30
53
|
# Please use .push if possible instead.
|
@@ -33,16 +56,10 @@ module Sidekiq
|
|
33
56
|
#
|
34
57
|
# Sidekiq::Client.enqueue(MyWorker, 'foo', 1, :bat => 'bar')
|
35
58
|
#
|
36
|
-
# Messages are enqueued to the 'default' queue.
|
37
|
-
# MyWorker can define a queue class method:
|
38
|
-
#
|
39
|
-
# def self.queue
|
40
|
-
# 'my_queue'
|
41
|
-
# end
|
59
|
+
# Messages are enqueued to the 'default' queue.
|
42
60
|
#
|
43
61
|
def self.enqueue(klass, *args)
|
44
|
-
|
45
|
-
push(queue, { 'class' => klass.name, 'args' => args })
|
62
|
+
push(nil, { 'class' => klass.name, 'args' => args })
|
46
63
|
end
|
47
64
|
end
|
48
65
|
end
|
data/lib/sidekiq/manager.rb
CHANGED
@@ -18,22 +18,20 @@ module Sidekiq
|
|
18
18
|
|
19
19
|
trap_exit :processor_died
|
20
20
|
|
21
|
-
|
22
|
-
|
23
|
-
|
21
|
+
class << self
|
22
|
+
attr_accessor :redis
|
23
|
+
end
|
24
|
+
|
25
|
+
def initialize(options={})
|
26
|
+
logger.info "Booting sidekiq #{Sidekiq::VERSION} with Redis at #{redis.client.location}"
|
27
|
+
logger.debug { options.inspect }
|
24
28
|
@count = options[:processor_count] || 25
|
25
29
|
@queues = options[:queues]
|
26
|
-
@queue_idx = 0
|
27
|
-
@queues_size = @queues.size
|
28
|
-
@redis = Redis.connect(:url => location)
|
29
30
|
@done_callback = nil
|
30
31
|
|
31
32
|
@done = false
|
32
33
|
@busy = []
|
33
|
-
@ready =
|
34
|
-
@count.times do
|
35
|
-
@ready << Processor.new_link(current_actor)
|
36
|
-
end
|
34
|
+
@ready = @count.times.map { Processor.new_link(current_actor) }
|
37
35
|
end
|
38
36
|
|
39
37
|
def stop
|
@@ -44,35 +42,38 @@ module Sidekiq
|
|
44
42
|
after(5) do
|
45
43
|
signal(:shutdown)
|
46
44
|
end
|
45
|
+
|
46
|
+
redis.with_connection do |conn|
|
47
|
+
conn.smembers('workers').each do |name|
|
48
|
+
conn.srem('workers', name) if name =~ /:#{Process.pid}:/
|
49
|
+
end
|
50
|
+
end
|
47
51
|
end
|
48
52
|
|
49
53
|
def start
|
50
54
|
dispatch(true)
|
51
55
|
end
|
52
56
|
|
53
|
-
def when_done
|
54
|
-
@done_callback =
|
57
|
+
def when_done(&blk)
|
58
|
+
@done_callback = blk
|
55
59
|
end
|
56
60
|
|
57
61
|
def processor_done(processor)
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
62
|
+
watchdog('sidekiq processor_done crashed!') do
|
63
|
+
@done_callback.call(processor) if @done_callback
|
64
|
+
@busy.delete(processor)
|
65
|
+
if stopped?
|
66
|
+
processor.terminate
|
67
|
+
else
|
68
|
+
@ready << processor
|
69
|
+
end
|
70
|
+
dispatch
|
64
71
|
end
|
65
|
-
dispatch
|
66
72
|
end
|
67
73
|
|
68
74
|
def processor_died(processor, reason)
|
69
75
|
@busy.delete(processor)
|
70
76
|
|
71
|
-
if reason
|
72
|
-
log "Processor death: #{reason}"
|
73
|
-
log reason.backtrace.join("\n")
|
74
|
-
end
|
75
|
-
|
76
77
|
unless stopped?
|
77
78
|
@ready << Processor.new_link(current_actor)
|
78
79
|
dispatch
|
@@ -81,13 +82,12 @@ module Sidekiq
|
|
81
82
|
|
82
83
|
private
|
83
84
|
|
84
|
-
def find_work(
|
85
|
-
|
86
|
-
msg = @redis.lpop("queue:#{current_queue}")
|
85
|
+
def find_work(queue)
|
86
|
+
msg = redis.lpop("queue:#{queue}")
|
87
87
|
if msg
|
88
88
|
processor = @ready.pop
|
89
89
|
@busy << processor
|
90
|
-
processor.process!
|
90
|
+
processor.process!(MultiJson.decode(msg), queue)
|
91
91
|
end
|
92
92
|
!!msg
|
93
93
|
end
|
@@ -96,32 +96,22 @@ module Sidekiq
|
|
96
96
|
watchdog("Fatal error in sidekiq, dispatch loop died") do
|
97
97
|
return if stopped?
|
98
98
|
|
99
|
-
#
|
100
|
-
# Loop through the queues, looking for a message in each.
|
101
|
-
queue_idx = 0
|
102
|
-
found = false
|
99
|
+
# Dispatch loop
|
103
100
|
loop do
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
queue_idx += 1
|
109
|
-
|
110
|
-
# if we find no messages in any of the queues, we can break
|
111
|
-
# out of the loop. Otherwise we loop again.
|
112
|
-
lastq = (queue_idx % @queues.size == 0)
|
113
|
-
if lastq && !found
|
114
|
-
verbose('nothing to process'); break
|
115
|
-
elsif lastq
|
116
|
-
queue_idx = 0
|
117
|
-
found = false
|
101
|
+
break logger.debug('no processors') if @ready.empty?
|
102
|
+
found = false
|
103
|
+
@ready.size.times do
|
104
|
+
found ||= find_work(@queues.sample)
|
118
105
|
end
|
106
|
+
break logger.debug('nothing to process') unless found
|
119
107
|
end
|
120
108
|
|
121
109
|
# This is the polling loop that ensures we check Redis every
|
122
110
|
# second for work, even if there was nothing to do this time
|
123
111
|
# around.
|
124
|
-
after(1)
|
112
|
+
after(1) do
|
113
|
+
dispatch(schedule)
|
114
|
+
end if schedule
|
125
115
|
end
|
126
116
|
end
|
127
117
|
|