rock-queue 0.2.0 → 0.3.0

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/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