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 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.2.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 => :test
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
@@ -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
- attr_reader :adapter
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
- class Base
29
-
30
- # Initializes the whole thing and makes the connection to the
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
- # Initialize logger
49
- @@logger = Logger.new(options[:log].nil? ? STDOUT : options[:log])
50
- end
51
-
52
-
53
- # Pushes the value (in our case it should always be an object)
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
- # Returns Rock Queue logger
79
- def self.logger
80
- @@logger
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
- config = RockQueue::Config.settings
22
- rq = RockQueue::Base.new config.adapter, {:server => config.host, :port => config.port}
23
- rq.push self.class, id, method, *args
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::Base.logger.error "You need `beanstalk-client` gem to use the Beanstalkd rock-queue interface"
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
- @obj = Beanstalk::Pool.new(["#{options[:server]}:#{options[:port]}"])
14
+ @options = options
15
+ @addr = "#{options[:server]}:#{options[:port]}"
16
+ @obj = Beanstalk::Pool.new([@addr])
15
17
  end
16
18
 
17
- def pop
18
- loop
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::Base.logger.error "You need `delayed_job` gem to use the Delayed Job rock-queue interface"
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::Base.logger.error "You need `resque` gem to use the Resque rock-queue interface"
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 = :default
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 :default
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::Base.logger.error "You need `mail` gem to use the Email Notifier"
21
+ RockQueue.logger.error "You need `mail` gem to use the Email Notifier"
16
22
  end
17
23
 
18
- RockQueue::Base.logger.info "Sending e-mail message: #{error.message}"
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
@@ -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::Base.logger.info "=> Rock-queue worker initialized (#{worker})"
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
@@ -4,42 +4,50 @@ module RockQueue
4
4
  attr_accessor :verbose
5
5
 
6
6
  # Initialize connection to queue server
7
- def initialize
8
- config = RockQueue::Config.settings
9
- @queue = RockQueue::Base.new config.adapter, {
10
- :server => config.host,
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::Base.logger.info "=> Worker ready. Hold your horses!"
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
- @queue.receive do |queue|
24
- if queue
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::Base.logger.info "=> Processing class #{queue.object.name} with params: #{args.inspect}"
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::Base.logger.error "=> Processing fail! Retrying #{queue.fails.length}"
35
- RockQueue::Base.logger.error " Message: #{e.message}"
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
- - 2
7
+ - 3
8
8
  - 0
9
- version: 0.2.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-11 00:00:00 +02:00
17
+ date: 2010-05-28 00:00:00 +02:00
18
18
  default_executable:
19
19
  dependencies: []
20
20