rock-queue 0.1.3

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/LICENSE ADDED
File without changes
data/Rakefile ADDED
@@ -0,0 +1,59 @@
1
+ require 'rubygems'
2
+ require 'rake/gempackagetask'
3
+ require 'rubygems/specification'
4
+ require 'spec/rake/spectask'
5
+ require 'date'
6
+ $LOAD_PATH.unshift File.dirname(__FILE__) + '/lib'
7
+ require 'rock-queue/tasks'
8
+
9
+ GEM = "rock-queue"
10
+ GEM_VERSION = "0.1.3"
11
+ AUTHOR = "Grzegorz Kazulak"
12
+ EMAIL = "gregorz.kazulak@gmail.com"
13
+ HOMEPAGE = "http://github.com/grzegorzkazulak/rock-queue"
14
+ SUMMARY = "A unified interface for various messaging queues"
15
+
16
+ spec = Gem::Specification.new do |s|
17
+ s.name = GEM
18
+ s.version = GEM_VERSION
19
+ s.platform = Gem::Platform::RUBY
20
+ s.has_rdoc = true
21
+ s.extra_rdoc_files = ["LICENSE"]
22
+ s.summary = SUMMARY
23
+ s.description = s.summary
24
+ s.author = AUTHOR
25
+ s.email = EMAIL
26
+ s.homepage = HOMEPAGE
27
+
28
+ s.require_path = 'lib'
29
+ s.autorequire = GEM
30
+ s.files = %w(LICENSE Rakefile) + Dir.glob("{lib,specs}/**/*")
31
+ end
32
+
33
+ Rake::GemPackageTask.new(spec) do |pkg|
34
+ pkg.gem_spec = spec
35
+ end
36
+
37
+ desc "install the gem locally"
38
+ task :install => [:package] do
39
+ sh %{sudo gem install pkg/#{GEM}-#{GEM_VERSION}}
40
+ end
41
+
42
+ desc "create a gemspec file"
43
+ task :make_spec do
44
+ File.open("#{GEM}.gemspec", "w") do |file|
45
+ file.puts spec.to_ruby
46
+ end
47
+ end
48
+
49
+ desc "Run all examples (or a specific spec with TASK=spec/some_file.rb)"
50
+ Spec::Rake::SpecTask.new('spec') do |t|
51
+ t.spec_opts = ["-cfs"]
52
+ t.spec_files = begin
53
+ if ENV["TASK"]
54
+ ENV["TASK"].split(',').map { |task| "spec/**/#{task}_spec.rb" }
55
+ else
56
+ FileList['spec/**/*_spec.rb']
57
+ end
58
+ end
59
+ end
data/lib/rock-queue.rb ADDED
@@ -0,0 +1,77 @@
1
+ $:.unshift File.expand_path(File.dirname(__FILE__))
2
+ require 'logger'
3
+
4
+ module RockQueue
5
+
6
+ autoload :Config, 'rock-queue/config'
7
+
8
+ autoload :AbstractNotifier, 'rock-queue/notifiers/abstract_notifier'
9
+ autoload :Notifiers, 'rock-queue/notifiers'
10
+ autoload :EmailNotifier, 'rock-queue/notifiers/email_notifier'
11
+
12
+ autoload :Worker, 'rock-queue/worker'
13
+ autoload :QueueObject, 'rock-queue/queue_object'
14
+
15
+ # Adapters
16
+ autoload :Beanstalkd, 'rock-queue/adapters/beanstalkd'
17
+ autoload :ResqueQueue, 'rock-queue/adapters/resque'
18
+ autoload :DelayedJob, 'rock-queue/adapters/delayed_job'
19
+
20
+ autoload :AdapterNotSupported, 'rock-queue/errors'
21
+ autoload :NoClassError, 'rock-queue/errors'
22
+ autoload :QueueingServerNotRunning, 'rock-queue/errors'
23
+ autoload :ActiveRecordHelper, 'rock-queue/active_record_helper'
24
+
25
+ attr_reader :adapter
26
+
27
+ class Base
28
+
29
+ # Initializes the whole thing and makes the connection to the
30
+ # queueing server using selected adapter (passed as lowercased symbol)
31
+ def initialize(adapter, *options)
32
+ # Any better way to do this? :-)
33
+ options = options.first
34
+ if options.include?(:server) && options.include?(:port)
35
+ case adapter
36
+ when :beanstalkd
37
+ @adapter = Beanstalkd.new(options)
38
+ when :resque
39
+ @adapter = ResqueQueue.new(options)
40
+ when :delayed_job
41
+ @adapter = DelayedJob.new(options)
42
+ end
43
+ else
44
+ raise ArgumentError
45
+ end
46
+ end
47
+
48
+
49
+ # Pushes the value (in our case it should always be an object)
50
+ # onto the queue using previously selected adapter
51
+ def push(value, *options)
52
+ @adapter.push(value, options)
53
+ end
54
+
55
+
56
+ # Pulls the data off the queue. There are two ways to do so:
57
+ # - Call receive with no block (gets you a single item)
58
+ # - Pass a block to it (creates and endles loop that constantly pulls items from the queue as they become available)
59
+ # All calls to the queueing server are made through the previosuly selected adaper.
60
+ def receive
61
+ if block_given?
62
+ obj = @adapter.pop
63
+ if obj
64
+ yield QueueObject.new(obj)
65
+ end
66
+ else
67
+ raise 'No block given'
68
+ end
69
+ end
70
+
71
+
72
+ def method_missing(sym, *args, &block)
73
+ @adapter.send sym, *args, &block
74
+ end
75
+
76
+ end
77
+ end
@@ -0,0 +1,25 @@
1
+ require 'active_record'
2
+
3
+ module RockQueue
4
+ module ActiveRecordHelper
5
+ def self.included(base)
6
+ base.extend ClassMethods
7
+ base.send(:include, InstanceMethods)
8
+ end
9
+
10
+ module ClassMethods
11
+ def self.perform(id, method, *args)
12
+ find(id).send(method, *args)
13
+ end
14
+ end
15
+
16
+ module InstanceMethods
17
+ def async(method, *args)
18
+ config = RockQueue::Config.settings
19
+ rq = RockQueue::Base.new config.adapter, {:server => config.host, :port => config.port}
20
+ rq.push self.class, id, method, *args
21
+ end
22
+ end
23
+
24
+ end
25
+ end
@@ -0,0 +1,21 @@
1
+ begin
2
+ require "beanstalk-client"
3
+ rescue
4
+ puts "You need `beanstalk-client` gem to use the Beanstalkd rock-queue interface"
5
+ exit
6
+ end
7
+
8
+ module RockQueue
9
+ class Beanstalkd
10
+
11
+ attr_reader :obj
12
+
13
+ def initialize(options = {})
14
+ @obj = Beanstalk::Pool.new(["#{options[:server]}:#{options[:port]}"])
15
+ end
16
+
17
+ def pop
18
+ loop
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,24 @@
1
+ begin
2
+ require "delayed_job"
3
+ rescue
4
+ puts "You need `delayed_job` gem to use the Delayed Job rock-queue interface"
5
+ exit
6
+ end
7
+
8
+ module RockQueue
9
+ class DelayedJob
10
+
11
+ attr_reader :obj
12
+
13
+ def initialize(options = {})
14
+ end
15
+
16
+ def push(value, options)
17
+ Delayed::Job.enqueue value
18
+ end
19
+
20
+ def pop
21
+
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,33 @@
1
+ begin
2
+ require 'resque'
3
+ rescue
4
+ puts "You need `resque` gem to use the Resque rock-queue interface"
5
+ exit
6
+ end
7
+
8
+ module RockQueue
9
+ class ResqueQueue
10
+
11
+ attr_reader :obj
12
+
13
+ def initialize(options)
14
+ Resque.redis = "#{options[:server]}:#{options[:port]}"
15
+ end
16
+
17
+ def push(value, options)
18
+ if !defined?(value.queue)
19
+ value.class_eval do
20
+ @queue = :default
21
+ end
22
+ end
23
+ Resque.enqueue value
24
+ end
25
+
26
+ def pop
27
+ job = Resque.reserve :default
28
+ if job
29
+ job.payload_class
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,30 @@
1
+ module RockQueue
2
+ class Config
3
+
4
+ attr_accessor :adapter, :host, :port
5
+
6
+ # Return the instance
7
+ def self.instance
8
+ @__instance__ ||= new
9
+ end
10
+
11
+ # Yields a singleton instance of RockQueue::Config so you can specify config
12
+ # information like server address, port etc.
13
+ def self.settings
14
+ if block_given?
15
+ yield self.instance
16
+ else
17
+ self.instance
18
+ end
19
+ end
20
+
21
+ def notifiers
22
+ if block_given?
23
+ yield Notifiers.instance
24
+ else
25
+ Notifiers.instance
26
+ end
27
+ end
28
+
29
+ end
30
+ end
@@ -0,0 +1,5 @@
1
+ module RockQueue
2
+ class AdapterNotSupported < RuntimeError; end
3
+ class NoClassError < RuntimeError; end
4
+ class QueueingServerNotRunning < RuntimeError; end
5
+ end
@@ -0,0 +1,23 @@
1
+ require "observer"
2
+
3
+ module RockQueue
4
+ class Notifiers
5
+ include Observable
6
+
7
+ # Return the instance of notifiers registry.
8
+ def self.instance
9
+ @__instance__ ||= new
10
+ end
11
+
12
+ # Registers the observer. You have to pass the instance of your notifier.
13
+ def register(instance)
14
+ add_observer instance
15
+ end
16
+
17
+ # Notifies all the observers
18
+ def notify(message)
19
+ changed
20
+ notify_observers message
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,2 @@
1
+ # AbstractNotifier is a base class (interface) for all your notifiers.
2
+ class AbstractNotifier; end
@@ -0,0 +1,40 @@
1
+ module RockQueue
2
+
3
+ class EmailNotifier < AbstractNotifier
4
+
5
+ def initialize(config)
6
+ $server_config = config
7
+ end
8
+
9
+ # Notify by email
10
+ def update(message)
11
+
12
+ begin
13
+ require 'mail'
14
+ rescue
15
+ puts "You need `mail` gem to use the Email Notifier"
16
+ end
17
+
18
+ puts "Sending e-mail message: #{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
+
28
+
29
+ end
30
+
31
+ Mail.deliver do
32
+ from $server_config[:from]
33
+ to $server_config[:to]
34
+ subject 'Processing error'
35
+ body message.to_s
36
+ end
37
+ end
38
+
39
+ end
40
+ end
@@ -0,0 +1,32 @@
1
+ module RockQueue
2
+
3
+ # Queue object wrapper
4
+ class QueueObject
5
+
6
+ DEFAULT_FAIL_LIMIT = 3
7
+
8
+ attr_reader :object, :fails
9
+
10
+ def initialize(object)
11
+ @object = object
12
+ @fails = Array.new
13
+ end
14
+
15
+ # Add processing fail
16
+ def add_fail(exception)
17
+ @fails << exception
18
+ if @fails.length < DEFAULT_FAIL_LIMIT
19
+ return true
20
+ else
21
+ RockQueue::Notifiers.instance.notify(exception)
22
+ end
23
+ end
24
+
25
+ # Get sleep time after fail
26
+ def get_sleep_time
27
+ 2 ** @fails.length
28
+ end
29
+
30
+ end
31
+
32
+ end
@@ -0,0 +1,11 @@
1
+ require 'rock-queue'
2
+
3
+ namespace :rock_queue do
4
+ desc "Start a Rock Queue worker"
5
+ task :work do
6
+ worker = RockQueue::Worker.new
7
+ worker.verbose = ENV['VERBOSE']
8
+ puts "=> Rock-queue worker initialized (#{worker})"
9
+ worker.work
10
+ end
11
+ end
@@ -0,0 +1,25 @@
1
+ require 'rubygems'
2
+ require 'sinatra/base'
3
+ require 'erb'
4
+
5
+ module RockQueue
6
+ class Web < Sinatra::Base
7
+
8
+ configure do
9
+ current_dir = File.dirname(File.expand_path(__FILE__))
10
+ set :views, "#{current_dir}/web/views"
11
+ set :public, "#{current_dir}/web/public"
12
+ set :static, true
13
+ set :raise_errors, true
14
+ end
15
+
16
+ get '/' do
17
+ redirect '/dashboard'
18
+ end
19
+
20
+ get '/dashboard' do
21
+ erb :dashboard
22
+ end
23
+
24
+ end
25
+ end
@@ -0,0 +1,31 @@
1
+ <html>
2
+ <head>
3
+ <title>Rock Queue - Web interface</title>
4
+ <style>
5
+ body {
6
+ font-family: Helvetica, sans-serif;
7
+ }
8
+
9
+ h1{
10
+ font-size: 24px;
11
+ }
12
+ h2 {
13
+ font-size: 14px;
14
+ }
15
+ </style>
16
+ </head>
17
+ <body>
18
+ <h1>RockQueue Web Interface</h1>
19
+
20
+ <% @workers = ['192.168.0.1:4344', '192.168.0.1:3434', '192.168.0.1:2333'] %>
21
+
22
+ <h2>Workers list</h2>
23
+ <ul>
24
+ <% for worker in @workers do %>
25
+ <li>
26
+ <%= worker %>
27
+ </li>
28
+ <% end %>
29
+ </ul>
30
+ </body>
31
+ </html>
@@ -0,0 +1,40 @@
1
+ module RockQueue
2
+ class Worker
3
+ # Whether the worker should log basic info to STDOUT
4
+ attr_accessor :verbose
5
+
6
+ # Initialize connection to queue server
7
+ def initialize
8
+ puts "=> Initializing..."
9
+ config = RockQueue::Config.settings
10
+ @queue = RockQueue::Base.new config.adapter, {
11
+ :server => config.host,
12
+ :port => config.port
13
+ }
14
+ end
15
+
16
+ # Main worker loop where all jobs are beeing pulled of the queue.
17
+ # This is also a place where every job starts and ends it's lifecycle.
18
+ def work
19
+ puts "=> Worker ready. Hold your horses!"
20
+ loop do
21
+ @queue.receive do |queue|
22
+ if queue
23
+ # code that actually performs the action
24
+ begin
25
+ queue.object.perform
26
+ rescue Object => e
27
+ # Add failed processing and retry
28
+ if queue.add_fail(e)
29
+ sleep(queue.get_sleep_time)
30
+ puts "=> Processing fail! Retrying #{queue.fails.length}"
31
+ retry
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+
39
+ end
40
+ end
metadata ADDED
@@ -0,0 +1,71 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rock-queue
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.3
5
+ platform: ruby
6
+ authors:
7
+ - Grzegorz Kazulak
8
+ autorequire: rock-queue
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-11-17 00:00:00 +01:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: A unified interface for various messaging queues
17
+ email: gregorz.kazulak@gmail.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - LICENSE
24
+ files:
25
+ - LICENSE
26
+ - Rakefile
27
+ - lib/rock-queue/active_record_helper.rb
28
+ - lib/rock-queue/adapters/beanstalkd.rb
29
+ - lib/rock-queue/adapters/delayed_job.rb
30
+ - lib/rock-queue/adapters/resque.rb
31
+ - lib/rock-queue/config.rb
32
+ - lib/rock-queue/errors.rb
33
+ - lib/rock-queue/notifiers/abstract_notifier.rb
34
+ - lib/rock-queue/notifiers/email_notifier.rb
35
+ - lib/rock-queue/notifiers.rb
36
+ - lib/rock-queue/queue_object.rb
37
+ - lib/rock-queue/tasks.rb
38
+ - lib/rock-queue/web/views/dashboard.erb
39
+ - lib/rock-queue/web.rb
40
+ - lib/rock-queue/worker.rb
41
+ - lib/rock-queue.rb
42
+ has_rdoc: true
43
+ homepage: http://github.com/grzegorzkazulak/rock-queue
44
+ licenses: []
45
+
46
+ post_install_message:
47
+ rdoc_options: []
48
+
49
+ require_paths:
50
+ - lib
51
+ required_ruby_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: "0"
56
+ version:
57
+ required_rubygems_version: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: "0"
62
+ version:
63
+ requirements: []
64
+
65
+ rubyforge_project:
66
+ rubygems_version: 1.3.5
67
+ signing_key:
68
+ specification_version: 3
69
+ summary: A unified interface for various messaging queues
70
+ test_files: []
71
+