rock-queue 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +18 -4
- data/lib/rock-queue.rb +54 -53
- data/lib/rock-queue/active_record_helper.rb +10 -4
- data/lib/rock-queue/adapters/beanstalkd.rb +29 -6
- data/lib/rock-queue/adapters/delayed_job.rb +3 -4
- data/lib/rock-queue/adapters/resque.rb +34 -5
- data/lib/rock-queue/notifiers/email_notifier.rb +13 -18
- data/lib/rock-queue/tasks.rb +2 -2
- data/lib/rock-queue/worker.rb +25 -17
- metadata +3 -3
data/Rakefile
CHANGED
@@ -5,9 +5,9 @@ require 'spec/rake/spectask'
|
|
5
5
|
require 'date'
|
6
6
|
$LOAD_PATH.unshift 'lib'
|
7
7
|
require 'rock-queue/tasks'
|
8
|
-
|
8
|
+
|
9
9
|
GEM = "rock-queue"
|
10
|
-
GEM_VERSION = "0.
|
10
|
+
GEM_VERSION = "0.3.0"
|
11
11
|
AUTHOR = "Grzegorz Kazulak"
|
12
12
|
EMAIL = "gregorz.kazulak@gmail.com"
|
13
13
|
HOMEPAGE = "http://github.com/grzegorzkazulak/rock-queue"
|
@@ -34,7 +34,7 @@ Rake::GemPackageTask.new(spec) do |pkg|
|
|
34
34
|
pkg.gem_spec = spec
|
35
35
|
end
|
36
36
|
|
37
|
-
task :default => :
|
37
|
+
task :default => :spec
|
38
38
|
|
39
39
|
desc "install the gem locally"
|
40
40
|
task :install => [:package] do
|
@@ -56,4 +56,18 @@ task :test do
|
|
56
56
|
Dir['test/*_test.rb'].each do |f|
|
57
57
|
require f
|
58
58
|
end
|
59
|
-
end
|
59
|
+
end
|
60
|
+
|
61
|
+
desc "Run all examples"
|
62
|
+
Spec::Rake::SpecTask.new('spec') do |t|
|
63
|
+
t.spec_opts = ["-cfs"]
|
64
|
+
t.spec_files = FileList['spec/**/*_spec.rb']
|
65
|
+
end
|
66
|
+
|
67
|
+
desc "Run all examples with RCov"
|
68
|
+
Spec::Rake::SpecTask.new('spec:rcov') do |t|
|
69
|
+
t.spec_opts = ["-cfs"]
|
70
|
+
t.rcov = true
|
71
|
+
t.spec_files = FileList['spec/**/*_spec.rb']
|
72
|
+
t.rcov_opts = ['--exclude spec,/home']
|
73
|
+
end
|
data/lib/rock-queue.rb
CHANGED
@@ -2,9 +2,7 @@ $:.unshift File.expand_path(File.dirname(__FILE__))
|
|
2
2
|
require 'logger'
|
3
3
|
|
4
4
|
module RockQueue
|
5
|
-
|
6
5
|
autoload :Config, 'rock-queue/config'
|
7
|
-
|
8
6
|
autoload :AbstractNotifier, 'rock-queue/notifiers/abstract_notifier'
|
9
7
|
autoload :Notifiers, 'rock-queue/notifiers'
|
10
8
|
autoload :EmailNotifier, 'rock-queue/notifiers/email_notifier'
|
@@ -22,64 +20,67 @@ module RockQueue
|
|
22
20
|
autoload :QueueingServerNotRunning, 'rock-queue/errors'
|
23
21
|
autoload :ActiveRecordHelper, 'rock-queue/active_record_helper'
|
24
22
|
|
25
|
-
|
23
|
+
extend self
|
26
24
|
|
25
|
+
# setup a connection
|
26
|
+
# options: adapter, server, port, log
|
27
|
+
def setup(options)
|
28
|
+
case options[:adapter]
|
29
|
+
when :beanstalkd
|
30
|
+
@adapter = Beanstalkd.new(options)
|
31
|
+
when :resque
|
32
|
+
@adapter = ResqueQueue.new(options)
|
33
|
+
when :delayed_job
|
34
|
+
@adapter = DelayedJob.new(options)
|
35
|
+
else
|
36
|
+
raise ArgumentError
|
37
|
+
end
|
38
|
+
@logger = Logger.new(options[:log].nil? ? STDOUT : options[:log])
|
39
|
+
end
|
27
40
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
# queueing server using selected adapter (passed as lowercased symbol)
|
32
|
-
def initialize(adapter, *options)
|
33
|
-
# Any better way to do this? :-)
|
34
|
-
options = options.first
|
35
|
-
if options.include?(:server) && options.include?(:port)
|
36
|
-
case adapter
|
37
|
-
when :beanstalkd
|
38
|
-
@adapter = Beanstalkd.new(options)
|
39
|
-
when :resque
|
40
|
-
@adapter = ResqueQueue.new(options)
|
41
|
-
when :delayed_job
|
42
|
-
@adapter = DelayedJob.new(options)
|
43
|
-
end
|
44
|
-
else
|
45
|
-
raise ArgumentError
|
46
|
-
end
|
41
|
+
def disconnect
|
42
|
+
@adapter = nil
|
43
|
+
end
|
47
44
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
# onto the queue using previously selected adapter
|
55
|
-
def push(value, *args)
|
56
|
-
@adapter.push(value, args)
|
57
|
-
end
|
58
|
-
|
59
|
-
|
60
|
-
# Pulls the data off the queue. There are two ways to do so:
|
61
|
-
# - Call receive with no block (gets you a single item)
|
62
|
-
# - Pass a block to it (creates and endles loop that constantly pulls items from the queue as they become available)
|
63
|
-
# All calls to the queueing server are made through the previosuly selected adaper.
|
64
|
-
def receive
|
65
|
-
if block_given?
|
66
|
-
obj, args = @adapter.pop
|
67
|
-
yield QueueObject.new(obj, args) if obj
|
68
|
-
else
|
69
|
-
raise 'No block given'
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
# Calling adapter method
|
74
|
-
def method_missing(sym, *args, &block)
|
75
|
-
@adapter.send sym, *args, &block
|
45
|
+
# return current connection
|
46
|
+
def adapter
|
47
|
+
if @adapter
|
48
|
+
@adapter
|
49
|
+
else
|
50
|
+
raise RuntimeError, "RockQueue is not connected. Use setup"
|
76
51
|
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def push(queue, value, *args)
|
55
|
+
adapter.push(queue, value, args)
|
56
|
+
end
|
77
57
|
|
78
|
-
|
79
|
-
|
80
|
-
|
58
|
+
def logger
|
59
|
+
@logger
|
60
|
+
end
|
61
|
+
|
62
|
+
# Pulls the data off the queue. There are two ways to do so:
|
63
|
+
# - Call receive with no block (gets you a single item)
|
64
|
+
# - Pass a block to it (creates and endles loop that constantly pulls
|
65
|
+
# items from the queue as they become available)
|
66
|
+
# All calls to the queueing server are made through the previosuly
|
67
|
+
# selecte adaper.
|
68
|
+
def receive(queue)
|
69
|
+
if block_given?
|
70
|
+
obj, args = @adapter.pop(queue)
|
71
|
+
yield QueueObject.new(obj, args) if obj
|
72
|
+
else
|
73
|
+
raise 'No block given'
|
81
74
|
end
|
75
|
+
end
|
82
76
|
|
77
|
+
# Register worker for web interface
|
78
|
+
def register_worker(worker)
|
79
|
+
@adapter.register_worker(worker) if @adapter.respond_to?(:register_worker)
|
83
80
|
end
|
84
81
|
|
82
|
+
# Calling adapter method
|
83
|
+
def method_missing(sym, *args, &block)
|
84
|
+
adapter.send sym, *args, &block
|
85
|
+
end
|
85
86
|
end
|
@@ -14,15 +14,21 @@ module RockQueue
|
|
14
14
|
method = args.shift
|
15
15
|
find(id).send(method, *args)
|
16
16
|
end
|
17
|
+
|
18
|
+
def queue
|
19
|
+
const_defined?(:QUEUE) ? self::QUEUE : :default
|
20
|
+
end
|
17
21
|
end
|
18
22
|
|
19
23
|
module InstanceMethods
|
20
24
|
def async(method, *args)
|
21
|
-
|
22
|
-
|
23
|
-
|
25
|
+
RockQueue.push self.class.queue, self.class, id, method, *args
|
26
|
+
end
|
27
|
+
|
28
|
+
def async_at(method, time_to_run_at, *args)
|
29
|
+
RockQueue.push_at(
|
30
|
+
self.class.queue, self.class, time_to_run_at, id, method, *args)
|
24
31
|
end
|
25
32
|
end
|
26
|
-
|
27
33
|
end
|
28
34
|
end
|
@@ -1,21 +1,44 @@
|
|
1
1
|
begin
|
2
2
|
require "beanstalk-client"
|
3
3
|
rescue
|
4
|
-
RockQueue
|
4
|
+
RockQueue.logger.error "You need `beanstalk-client` gem to use" \
|
5
|
+
"the Beanstalkd rock-queue interface"
|
5
6
|
exit
|
6
7
|
end
|
7
8
|
|
8
9
|
module RockQueue
|
9
10
|
class Beanstalkd
|
10
|
-
|
11
11
|
attr_reader :obj
|
12
12
|
|
13
13
|
def initialize(options = {})
|
14
|
-
@
|
14
|
+
@options = options
|
15
|
+
@addr = "#{options[:server]}:#{options[:port]}"
|
16
|
+
@obj = Beanstalk::Pool.new([@addr])
|
15
17
|
end
|
16
18
|
|
17
|
-
def
|
18
|
-
|
19
|
+
def push(queue, value, *args)
|
20
|
+
@obj.send(:send_to_rand_conn, :use, queue)
|
21
|
+
@obj.put [value.name, args].to_yaml
|
22
|
+
end
|
23
|
+
|
24
|
+
def pop(queue)
|
25
|
+
@obj.send(:send_to_rand_conn, :use, queue)
|
26
|
+
r = YAML.load(@obj.reserve.body)
|
27
|
+
r[0] = Kernel.const_get(r[0])
|
28
|
+
r
|
19
29
|
end
|
30
|
+
|
31
|
+
def clear
|
32
|
+
system "pkill beanstalkd"
|
33
|
+
system "beanstalkd -d -p #{@options[:port]}"
|
34
|
+
end
|
35
|
+
|
36
|
+
def size(queue)
|
37
|
+
@obj.stats_tube(queue)["current-jobs-ready"]
|
38
|
+
end
|
39
|
+
|
40
|
+
def queues
|
41
|
+
@obj.list_tubes[@addr].map(&:to_sym)
|
42
|
+
end
|
20
43
|
end
|
21
|
-
end
|
44
|
+
end
|
@@ -1,13 +1,13 @@
|
|
1
1
|
begin
|
2
2
|
require "delayed_job"
|
3
3
|
rescue
|
4
|
-
RockQueue
|
4
|
+
RockQueue.logger.error "You need `delayed_job` gem to use" \
|
5
|
+
"the Delayed Job rock-queue interface"
|
5
6
|
exit
|
6
7
|
end
|
7
8
|
|
8
9
|
module RockQueue
|
9
10
|
class DelayedJob
|
10
|
-
|
11
11
|
attr_reader :obj
|
12
12
|
|
13
13
|
def initialize(options = {})
|
@@ -18,7 +18,6 @@ module RockQueue
|
|
18
18
|
end
|
19
19
|
|
20
20
|
def pop
|
21
|
-
|
22
21
|
end
|
23
22
|
end
|
24
|
-
end
|
23
|
+
end
|
@@ -1,7 +1,8 @@
|
|
1
1
|
begin
|
2
2
|
require 'resque'
|
3
3
|
rescue
|
4
|
-
RockQueue
|
4
|
+
RockQueue.logger.error "You need `resque` gem to use" \
|
5
|
+
"the Resque rock-queue interface"
|
5
6
|
exit
|
6
7
|
end
|
7
8
|
|
@@ -13,23 +14,51 @@ module RockQueue
|
|
13
14
|
# Contructor of Resque adapter
|
14
15
|
def initialize(options)
|
15
16
|
Resque.redis = "#{options[:server]}:#{options[:port]}"
|
17
|
+
Resque.redis.sadd(:queues, :default)
|
16
18
|
end
|
17
19
|
|
18
20
|
# Push item from Resque queue
|
19
|
-
def push(value, args)
|
21
|
+
def push(queue, value, args)
|
20
22
|
if !defined?(value.queue)
|
21
23
|
value.class_eval do
|
22
|
-
@queue =
|
24
|
+
@queue = queue
|
23
25
|
end
|
24
26
|
end
|
25
27
|
Resque.enqueue value, args
|
26
28
|
end
|
29
|
+
|
30
|
+
# Push items to Resque queue to be picked up by the worker on specified time
|
31
|
+
def push_at(value, time_to_run_at ,*args)
|
32
|
+
if !defined?(value.queue)
|
33
|
+
value.class_eval do
|
34
|
+
@queue = :default
|
35
|
+
end
|
36
|
+
end
|
37
|
+
Resque.enqueue_at time_to_run_at, value, args
|
38
|
+
end
|
27
39
|
|
28
40
|
# Retrieve item from Resque queue
|
29
|
-
def pop
|
30
|
-
job = Resque.reserve
|
41
|
+
def pop(queue)
|
42
|
+
job = Resque.reserve(queue)
|
31
43
|
[job.payload_class, job.args] if job
|
32
44
|
end
|
33
45
|
|
46
|
+
# Register worker for web interface
|
47
|
+
def register_worker(worker)
|
48
|
+
Resque.redis.sadd(:workers, worker)
|
49
|
+
end
|
50
|
+
|
51
|
+
def clear
|
52
|
+
Resque.redis.flushall
|
53
|
+
Resque.redis.sadd(:queues, :default)
|
54
|
+
end
|
55
|
+
|
56
|
+
def size(queue)
|
57
|
+
Resque.size(queue)
|
58
|
+
end
|
59
|
+
|
60
|
+
def queues
|
61
|
+
Resque.queues.sort.map(&:to_sym)
|
62
|
+
end
|
34
63
|
end
|
35
64
|
end
|
@@ -1,39 +1,34 @@
|
|
1
1
|
module RockQueue
|
2
|
-
|
3
2
|
class EmailNotifier < AbstractNotifier
|
4
|
-
|
5
3
|
def initialize(config)
|
6
4
|
$server_config = config
|
5
|
+
|
6
|
+
Mail.defaults do
|
7
|
+
delivery_method :smtp, {
|
8
|
+
:address => $server_config[:server],
|
9
|
+
:port => $server_config[:port],
|
10
|
+
:user_name => $server_config[:username],
|
11
|
+
:password => $server_config[:password]
|
12
|
+
}
|
13
|
+
end
|
7
14
|
end
|
8
15
|
|
9
16
|
# Notify by email
|
10
17
|
def update(error)
|
11
|
-
|
12
18
|
begin
|
13
19
|
require 'mail'
|
14
20
|
rescue
|
15
|
-
RockQueue
|
21
|
+
RockQueue.logger.error "You need `mail` gem to use the Email Notifier"
|
16
22
|
end
|
17
23
|
|
18
|
-
RockQueue
|
19
|
-
|
20
|
-
Mail.defaults do
|
21
|
-
smtp do
|
22
|
-
host $server_config[:server]
|
23
|
-
port $server_config[:port]
|
24
|
-
user $server_config[:username]
|
25
|
-
pass $server_config[:password]
|
26
|
-
end
|
27
|
-
end
|
24
|
+
RockQueue.logger.info "Sending e-mail message: #{error.message}"
|
28
25
|
|
29
26
|
Mail.deliver do
|
30
27
|
from $server_config[:from]
|
31
28
|
to $server_config[:to]
|
32
|
-
subject "Processing error - '#{error.message}'
|
29
|
+
subject "Processing error - '#{error.message}'"
|
33
30
|
body error.backtrace.join("\n")
|
34
31
|
end
|
35
|
-
|
36
32
|
end
|
37
|
-
|
38
33
|
end
|
39
|
-
end
|
34
|
+
end
|
data/lib/rock-queue/tasks.rb
CHANGED
@@ -9,9 +9,9 @@ namespace :rock_queue do
|
|
9
9
|
file_path = "#{RAILS_ROOT}/tmp/pids/rock-queue.pid"
|
10
10
|
|
11
11
|
task :work do
|
12
|
-
worker = RockQueue::Worker.new
|
12
|
+
worker = RockQueue::Worker.new(ENV['QUEUE'].split(/,/))
|
13
13
|
worker.verbose = ENV['VERBOSE']
|
14
|
-
RockQueue
|
14
|
+
RockQueue.logger.info "=> Rock-queue worker initialized (#{worker})"
|
15
15
|
pid = fork do
|
16
16
|
File.open(file_path, "wb") { |f| f.write(Process.pid) }
|
17
17
|
worker.work
|
data/lib/rock-queue/worker.rb
CHANGED
@@ -4,42 +4,50 @@ module RockQueue
|
|
4
4
|
attr_accessor :verbose
|
5
5
|
|
6
6
|
# Initialize connection to queue server
|
7
|
-
def initialize
|
8
|
-
|
9
|
-
@
|
10
|
-
|
11
|
-
:port => config.port,
|
12
|
-
:log => config.log
|
13
|
-
}
|
14
|
-
RockQueue::Base.logger.info "=> Initializing..."
|
7
|
+
def initialize(*queues)
|
8
|
+
queues = [:default] if queues.size == 0
|
9
|
+
@queues = queues
|
10
|
+
RockQueue.logger.info "=> Initializing..."
|
15
11
|
end
|
16
12
|
|
17
13
|
# Main worker loop where all jobs are beeing pulled of the queue.
|
18
14
|
# This is also a place where every job starts and ends it's lifecycle.
|
19
|
-
def work
|
20
|
-
RockQueue
|
15
|
+
def work(interval = 5)
|
16
|
+
RockQueue.logger.info "=> Worker ready. Hold your horses!"
|
17
|
+
stop = false
|
21
18
|
loop do
|
22
19
|
ActiveRecord::Base.verify_active_connections!
|
23
|
-
|
24
|
-
|
20
|
+
queues.each do |qname|
|
21
|
+
obj, args = RockQueue.pop(qname)
|
22
|
+
if obj
|
23
|
+
queue = QueueObject.new(obj, args)
|
25
24
|
begin
|
26
25
|
# code that actually performs the action
|
27
26
|
args = queue.args.first
|
28
|
-
RockQueue
|
27
|
+
RockQueue.logger.info "=> Processing class #{queue.object.name} with params: #{args.inspect}"
|
29
28
|
args.empty? ? queue.object.perform : queue.object.perform(args)
|
30
29
|
rescue Object => e
|
31
30
|
# Add failed processing and retry
|
32
31
|
if queue.add_fail(e)
|
33
32
|
sleep(queue.get_sleep_time)
|
34
|
-
RockQueue
|
35
|
-
RockQueue
|
33
|
+
RockQueue.logger.error "=> Processing fail! Retrying #{queue.fails.length}"
|
34
|
+
RockQueue.logger.error " Message: #{e.message}"
|
36
35
|
retry
|
37
36
|
end
|
38
37
|
end
|
38
|
+
stop = false
|
39
|
+
else
|
40
|
+
stop = true if interval == 0
|
39
41
|
end
|
40
42
|
end
|
43
|
+
break if stop
|
41
44
|
end
|
42
45
|
end
|
43
|
-
|
46
|
+
|
47
|
+
# Returns a list of queues
|
48
|
+
# A single '*' means all queues
|
49
|
+
def queues
|
50
|
+
@queues[0] == "*" ? RockQueue.queues : @queues
|
51
|
+
end
|
44
52
|
end
|
45
|
-
end
|
53
|
+
end
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
-
|
7
|
+
- 3
|
8
8
|
- 0
|
9
|
-
version: 0.
|
9
|
+
version: 0.3.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Grzegorz Kazulak
|
@@ -14,7 +14,7 @@ autorequire: rock-queue
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-05-
|
17
|
+
date: 2010-05-28 00:00:00 +02:00
|
18
18
|
default_executable:
|
19
19
|
dependencies: []
|
20
20
|
|