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 +0 -0
- data/Rakefile +59 -0
- data/lib/rock-queue.rb +77 -0
- data/lib/rock-queue/active_record_helper.rb +25 -0
- data/lib/rock-queue/adapters/beanstalkd.rb +21 -0
- data/lib/rock-queue/adapters/delayed_job.rb +24 -0
- data/lib/rock-queue/adapters/resque.rb +33 -0
- data/lib/rock-queue/config.rb +30 -0
- data/lib/rock-queue/errors.rb +5 -0
- data/lib/rock-queue/notifiers.rb +23 -0
- data/lib/rock-queue/notifiers/abstract_notifier.rb +2 -0
- data/lib/rock-queue/notifiers/email_notifier.rb +40 -0
- data/lib/rock-queue/queue_object.rb +32 -0
- data/lib/rock-queue/tasks.rb +11 -0
- data/lib/rock-queue/web.rb +25 -0
- data/lib/rock-queue/web/views/dashboard.erb +31 -0
- data/lib/rock-queue/worker.rb +40 -0
- metadata +71 -0
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,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,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,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
|
+
|