rabbithole 0.0.1
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.
- checksums.yaml +7 -0
- data/.coveralls.yml +1 -0
- data/.gitignore +17 -0
- data/.rspec +1 -0
- data/.travis.yml +15 -0
- data/Gemfile +15 -0
- data/Guardfile +9 -0
- data/LICENSE.txt +22 -0
- data/README.md +54 -0
- data/Rakefile +1 -0
- data/bin/rabbithole +5 -0
- data/lib/rabbithole/cli.rb +48 -0
- data/lib/rabbithole/connection.rb +64 -0
- data/lib/rabbithole/error_handler.rb +17 -0
- data/lib/rabbithole/error_handlers/null_handler.rb +9 -0
- data/lib/rabbithole/error_handlers/raise_handler.rb +9 -0
- data/lib/rabbithole/errors.rb +6 -0
- data/lib/rabbithole/version.rb +6 -0
- data/lib/rabbithole/worker.rb +38 -0
- data/lib/rabbithole.rb +32 -0
- data/rabbithole.gemspec +25 -0
- data/spec/fixtures/config/amqp.yml +7 -0
- data/spec/lib/rabbithole/connection_spec.rb +22 -0
- data/spec/lib/rabbithole/error_handlers/null_handler_spec.rb +25 -0
- data/spec/lib/rabbithole/error_handlers/raise_handler_spec.rb +27 -0
- data/spec/lib/rabbithole/worker_spec.rb +43 -0
- data/spec/lib/rabbithole_spec.rb +41 -0
- data/spec/spec_helper.rb +40 -0
- data/spec/support/fake_rails.rb +19 -0
- metadata +138 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 7e11d35fe87a9333074b8c70cf7a91711a9ebdc4
|
4
|
+
data.tar.gz: a076cc979a224222bd782f8621471ffed4269900
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 47c4e22b1ca425e9bc315a72fbc20f8ff32d5baa9864aab01c59f8f3a5ffa3717a9e54ce02348e3e033d1ac8874a74929be13d4da209b4a0d9473f1191542cac
|
7
|
+
data.tar.gz: 26d019f76e0e22f0b7c943c29f6d158f57340659baab6fd25844dcfc55d7028188346e4daacdeba79bce15c8c70a7b91c4ba8235e3b8b6129b983fc41fb0dafe
|
data/.coveralls.yml
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
service_name: travis-ci
|
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--order rand
|
data/.travis.yml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
nguage: ruby
|
2
|
+
bundler_args: --without development
|
3
|
+
script: "bundle exec rspec -cfs spec"
|
4
|
+
rvm:
|
5
|
+
- "2.0"
|
6
|
+
- "1.9.3"
|
7
|
+
- "1.8.7"
|
8
|
+
- "ree"
|
9
|
+
notifications:
|
10
|
+
email: mschaefermeyer@bleacherreport.com
|
11
|
+
services:
|
12
|
+
- rabbitmq
|
13
|
+
branches:
|
14
|
+
only:
|
15
|
+
- master
|
data/Gemfile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
gemspec
|
3
|
+
|
4
|
+
group :test do
|
5
|
+
gem 'bundler', '~> 1.3'
|
6
|
+
gem 'rake'
|
7
|
+
gem 'rspec', '~> 2.14'
|
8
|
+
gem 'coveralls', :require => false, :platform => [:ruby_19, :ruby_20]
|
9
|
+
gem 'pry', '~> 0.9'
|
10
|
+
end
|
11
|
+
|
12
|
+
group :development do
|
13
|
+
gem 'simplecov', '~> 0.7.1'
|
14
|
+
gem 'guard-rspec', '~> 4.0.3'
|
15
|
+
end
|
data/Guardfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Michael Schaefermeyer
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
# Rabbithole
|
2
|
+
[](https://travis-ci.org/mschae/rabbithole)
|
3
|
+
[](https://codeclimate.com/github/mschae/rabbithole)
|
4
|
+
[](https://coveralls.io/r/mschae/rabbithole)
|
5
|
+
[](https://gemnasium.com/mschae/rabbithole)
|
6
|
+
|
7
|
+
The idea of this gem is to mimick Resque: It can use the same worker classes and enqueueing works similar, too.
|
8
|
+
The reason is that I really like Resque and how it does things. The only problem with it is the backend. This is not what Redis is there for or any good in.
|
9
|
+
|
10
|
+
Rabbithole allows to switch from Resque to a RabbitMQ-based queueing system with ease. And it takes care of the heavy lifting.
|
11
|
+
|
12
|
+
I wrote it as part of my job with [Bleacher Report](http://bleacherreport.com), where we exceeded the scalability of Resque (or rather Redis).
|
13
|
+
|
14
|
+
Rabbithole currently only works with Rails, although I intend to make it work standalone at some point. Please note that it is WIP.
|
15
|
+
|
16
|
+
## Installation
|
17
|
+
|
18
|
+
Add this line to your application's Gemfile:
|
19
|
+
|
20
|
+
gem 'rabbithole'
|
21
|
+
|
22
|
+
And then execute:
|
23
|
+
|
24
|
+
$ bundle
|
25
|
+
|
26
|
+
Or install it yourself as:
|
27
|
+
|
28
|
+
$ gem install rabbithole
|
29
|
+
|
30
|
+
## Usage
|
31
|
+
|
32
|
+
Define a job, make sure it has a `perform` method:
|
33
|
+
```ruby
|
34
|
+
class MyAwesomeJob
|
35
|
+
def self.perform
|
36
|
+
# do awesome things
|
37
|
+
end
|
38
|
+
end
|
39
|
+
```
|
40
|
+
|
41
|
+
Enqueue the job:
|
42
|
+
```ruby
|
43
|
+
Rabbithole.enqueue MyAwesomeJob
|
44
|
+
```
|
45
|
+
|
46
|
+
Be done with it.
|
47
|
+
|
48
|
+
## Contributing
|
49
|
+
|
50
|
+
1. Fork it
|
51
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
52
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
53
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
54
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/bin/rabbithole
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'thor'
|
2
|
+
module Rabbithole
|
3
|
+
class CLI < Thor
|
4
|
+
desc 'work', 'Run the rabbithole worker. It listens to jobs and executes them.'
|
5
|
+
option :queues, :alias => :q, :type => :array, :required => true
|
6
|
+
option :num_workers, :alias => :n, :type => :numeric, :default => 1
|
7
|
+
option :require, :alias => :r, :type => :string, :default => '.'
|
8
|
+
|
9
|
+
def work
|
10
|
+
load_environment options[:require]
|
11
|
+
@worker = Worker.new(options[:num_workers])
|
12
|
+
queues = options[:queues]
|
13
|
+
queues << Rabbithole::Connection::DEFAULT_QUEUE if queues.delete('default') || queues.delete('*')
|
14
|
+
queues.each do |queue|
|
15
|
+
@worker.listen_to_queue(queue)
|
16
|
+
end
|
17
|
+
|
18
|
+
Signal.trap("INT") { shutdown }
|
19
|
+
|
20
|
+
@worker.join
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
protected
|
25
|
+
def shutdown
|
26
|
+
puts 'Worker shutting down gracefully...'
|
27
|
+
Thread.new { @worker.stop_listening }
|
28
|
+
end
|
29
|
+
|
30
|
+
# Entirely copied from resque
|
31
|
+
def load_environment(file)
|
32
|
+
if File.directory?(file) && File.exists?(File.expand_path("#{file}/config/environment.rb"))
|
33
|
+
require "rails"
|
34
|
+
require File.expand_path("#{file}/config/environment.rb")
|
35
|
+
if defined?(::Rails) && ::Rails.respond_to?(:application)
|
36
|
+
# Rails 3
|
37
|
+
::Rails.application.eager_load!
|
38
|
+
elsif defined?(::Rails::Initializer)
|
39
|
+
# Rails 2.3
|
40
|
+
$rails_rake_task = false
|
41
|
+
::Rails::Initializer.run :load_application_classes
|
42
|
+
end
|
43
|
+
elsif File.file?(file)
|
44
|
+
require File.expand_path(file)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'settingslogic'
|
2
|
+
require 'bunny'
|
3
|
+
|
4
|
+
module Rabbithole
|
5
|
+
class Connection
|
6
|
+
QUEUE_PREFIX = "rabbithole/#{Rails.application.class.parent_name.downcase}"
|
7
|
+
DEFAULT_QUEUE = 'default_queue'
|
8
|
+
|
9
|
+
class << self
|
10
|
+
def publish(queue_name, payload)
|
11
|
+
channel = create_channel
|
12
|
+
queue(queue_name)
|
13
|
+
channel.default_exchange.publish(payload, :routing_key => get_queue_name(queue_name))
|
14
|
+
channel.close
|
15
|
+
end
|
16
|
+
|
17
|
+
def default_queue
|
18
|
+
queue DEFAULT_QUEUE
|
19
|
+
end
|
20
|
+
|
21
|
+
def get_queue_name(queue)
|
22
|
+
"#{QUEUE_PREFIX}.#{queue}"
|
23
|
+
end
|
24
|
+
|
25
|
+
def queue(name, channel = self.channel)
|
26
|
+
channel.queue(get_queue_name(name), :durable => true)
|
27
|
+
end
|
28
|
+
|
29
|
+
def session
|
30
|
+
@connection ||=
|
31
|
+
begin
|
32
|
+
connection = Bunny.new(configuration)
|
33
|
+
connection.start
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def create_channel(worker_pool_size = 1, name = nil)
|
38
|
+
self.session.create_channel(name, worker_pool_size)
|
39
|
+
end
|
40
|
+
|
41
|
+
def configuration
|
42
|
+
@configuration ||= Settings.to_url
|
43
|
+
end
|
44
|
+
|
45
|
+
def channel
|
46
|
+
@channel ||= create_channel
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
class Settings < ::Settingslogic
|
51
|
+
source Rails.root.join('config', 'amqp.yml')
|
52
|
+
namespace Rails.env
|
53
|
+
|
54
|
+
def to_url
|
55
|
+
"amqp://#{user}:#{password}@#{host}:#{port}/#{vhost.gsub('/', '%2F')}"
|
56
|
+
end
|
57
|
+
|
58
|
+
# Fix rspec integration error
|
59
|
+
def to_ary
|
60
|
+
to_a
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Rabbithole
|
2
|
+
class ErrorHandler
|
3
|
+
class << self
|
4
|
+
@@registered_handler = Rabbithole::ErrorHandlers::RaiseHandler
|
5
|
+
|
6
|
+
def handle(error)
|
7
|
+
@@registered_handler.handle(error)
|
8
|
+
end
|
9
|
+
|
10
|
+
def register_handler(handler)
|
11
|
+
@@registered_handler = handler
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Rabbithole
|
2
|
+
class Worker
|
3
|
+
attr_reader :number_of_threads
|
4
|
+
|
5
|
+
def initialize(number_of_threads = 1)
|
6
|
+
@number_of_threads = number_of_threads
|
7
|
+
@channel = Connection.create_channel(number_of_threads)
|
8
|
+
end
|
9
|
+
|
10
|
+
def listen_to_queue(queue_name)
|
11
|
+
queue = Connection.queue(queue_name, @channel)
|
12
|
+
start_consumer(queue)
|
13
|
+
end
|
14
|
+
|
15
|
+
def stop_listening
|
16
|
+
@channel.consumers.values.each(&:cancel)
|
17
|
+
end
|
18
|
+
|
19
|
+
def join
|
20
|
+
@channel.work_pool.join
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
def start_consumer(queue)
|
25
|
+
queue.subscribe(:ack => true, :block => false) do |delivery_info, properties, payload|
|
26
|
+
data = MessagePack.unpack(payload)
|
27
|
+
begin
|
28
|
+
Object.const_get(data['klass']).perform(*data['args'])
|
29
|
+
@channel.acknowledge(delivery_info.delivery_tag, false)
|
30
|
+
rescue => e
|
31
|
+
@channel.reject(delivery_info.delivery_tag, !delivery_info.redelivered)
|
32
|
+
ErrorHandler.handle(e)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
data/lib/rabbithole.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
require "rabbithole/version"
|
2
|
+
require "rabbithole/errors"
|
3
|
+
require "msgpack"
|
4
|
+
|
5
|
+
module Rabbithole
|
6
|
+
autoload :Connection, 'rabbithole/connection'
|
7
|
+
autoload :Worker, 'rabbithole/worker'
|
8
|
+
autoload :ErrorHandler, 'rabbithole/error_handler'
|
9
|
+
autoload :CLI, 'rabbithole/cli'
|
10
|
+
module ErrorHandlers
|
11
|
+
autoload :NullHandler, 'rabbithole/error_handlers/null_handler'
|
12
|
+
autoload :RaiseHandler, 'rabbithole/error_handlers/raise_handler'
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.enqueue(klass, *args)
|
16
|
+
if klass.is_a?(Class)
|
17
|
+
if klass.respond_to?(:perform)
|
18
|
+
payload = {
|
19
|
+
:klass => klass.to_s,
|
20
|
+
:args => args
|
21
|
+
}.to_msgpack
|
22
|
+
|
23
|
+
queue = klass.instance_variable_defined?(:@queue) ? klass.instance_variable_get(:@queue) : Connection::DEFAULT_QUEUE
|
24
|
+
Connection.publish(queue, payload)
|
25
|
+
else
|
26
|
+
raise InvalidJobError.new("The class #{klass} does not define the method perform. I don't know how to execute it...")
|
27
|
+
end
|
28
|
+
else
|
29
|
+
raise UnknownJobError.new("The class #{klass} is not known to Rabbithole. Is it a class?")
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/rabbithole.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'rabbithole/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "rabbithole"
|
8
|
+
spec.version = Rabbithole::VERSION
|
9
|
+
spec.authors = ["Michael Schaefermeyer"]
|
10
|
+
spec.email = ["mschaefermeyer@bleacherreport.com"]
|
11
|
+
spec.description = %q{Rabbithole encapsulate logic to trigger and run asyncronous jobs using RabbitMQ}
|
12
|
+
spec.summary = %q{Rabbithole encapsulate logic to trigger and run asyncronous jobs using RabbitMQ}
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_dependency "bunny", "~> 1.0.0"
|
22
|
+
spec.add_dependency "settingslogic", "~> 2.0.9"
|
23
|
+
spec.add_dependency "msgpack", "~> 0.5"
|
24
|
+
spec.add_dependency "thor", "~> 0.18"
|
25
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Rabbithole::Connection do
|
4
|
+
describe Rabbithole::Connection::Settings do
|
5
|
+
it 'reads the correct config' do
|
6
|
+
Rabbithole::Connection::Settings.host.should == 'localhost'
|
7
|
+
Rabbithole::Connection::Settings.port.should == 5672
|
8
|
+
Rabbithole::Connection::Settings.vhost.should == '/rabbithole-test'
|
9
|
+
Rabbithole::Connection::Settings.user.should == 'rabbithole-test-user'
|
10
|
+
Rabbithole::Connection::Settings.password.should == 'rabbithole-test-password'
|
11
|
+
end
|
12
|
+
|
13
|
+
it '#to_url' do
|
14
|
+
Rabbithole::Connection::Settings.to_url.should == 'amqp://rabbithole-test-user:rabbithole-test-password@localhost:5672/%2Frabbithole-test'
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'establishes a connection' do
|
19
|
+
described_class.session
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Rabbithole::ErrorHandlers::NullHandler do
|
4
|
+
let(:worker){ Rabbithole::Worker.new }
|
5
|
+
before :each do
|
6
|
+
worker.listen_to_queue(Rabbithole::Connection::DEFAULT_QUEUE)
|
7
|
+
Rabbithole::ErrorHandler.register_handler described_class
|
8
|
+
end
|
9
|
+
|
10
|
+
after :each do
|
11
|
+
worker.stop_listening
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'does absolutely nothing on errors' do
|
15
|
+
class NullHandlerTestJob
|
16
|
+
def self.perform
|
17
|
+
raise 'hell'
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
Rabbithole.enqueue(NullHandlerTestJob)
|
22
|
+
sleep 0.5
|
23
|
+
Rabbithole::Connection.default_queue.message_count.should == 0
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Rabbithole::ErrorHandlers::RaiseHandler do
|
4
|
+
let(:worker){ Rabbithole::Worker.new }
|
5
|
+
before :each do
|
6
|
+
worker.listen_to_queue(Rabbithole::Connection::DEFAULT_QUEUE)
|
7
|
+
Rabbithole::ErrorHandler.register_handler described_class
|
8
|
+
end
|
9
|
+
|
10
|
+
after :each do
|
11
|
+
worker.stop_listening
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'should raise errors' do
|
15
|
+
class RaiseHandlerTestjob
|
16
|
+
def self.perform
|
17
|
+
raise 'hell'
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
expect {
|
22
|
+
Rabbithole.enqueue(RaiseHandlerTestjob)
|
23
|
+
sleep 0.5
|
24
|
+
}.to raise_error
|
25
|
+
Rabbithole::Connection.default_queue.message_count.should == 0
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Rabbithole::Worker do
|
4
|
+
before :each do
|
5
|
+
subject.listen_to_queue(Rabbithole::Connection::DEFAULT_QUEUE)
|
6
|
+
end
|
7
|
+
|
8
|
+
after :each do
|
9
|
+
subject.stop_listening
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'invokes the perform action' do
|
13
|
+
class InvokeTestJob
|
14
|
+
def self.perform; end
|
15
|
+
end
|
16
|
+
|
17
|
+
InvokeTestJob.should_receive(:perform)
|
18
|
+
Rabbithole.enqueue(InvokeTestJob)
|
19
|
+
sleep 0.5
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'passes the correct arguments to the perform action' do
|
23
|
+
class ArgumentsTestJob
|
24
|
+
def self.perform(arg1, arg2); end
|
25
|
+
end
|
26
|
+
|
27
|
+
ArgumentsTestJob.should_receive(:perform).with(1, 'a').once
|
28
|
+
Rabbithole.enqueue(ArgumentsTestJob, 1, 'a')
|
29
|
+
sleep 1
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'gracefully handles failing jobs' do
|
33
|
+
class HandlingFailsJob
|
34
|
+
def self.perform
|
35
|
+
raise 'hell'
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
Rabbithole::ErrorHandler.should_receive(:handle).twice
|
40
|
+
Rabbithole.enqueue(HandlingFailsJob)
|
41
|
+
sleep 0.5
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Rabbithole do
|
4
|
+
it 'enqueues well defined jobs' do
|
5
|
+
class FooJob
|
6
|
+
def self.perform(*args); end
|
7
|
+
end
|
8
|
+
|
9
|
+
expect {
|
10
|
+
described_class.enqueue(FooJob)
|
11
|
+
}.to change { Rabbithole::Connection.default_queue.message_count }.by 1
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'fails to enqueue a job that does not define a perform method' do
|
15
|
+
class BazClass
|
16
|
+
end
|
17
|
+
|
18
|
+
expect do
|
19
|
+
expect { described_class.enqueue(BazClass) }.to raise_error Rabbithole::InvalidJobError
|
20
|
+
end.to_not change {Rabbithole::Connection.default_queue.message_count }
|
21
|
+
end
|
22
|
+
|
23
|
+
context 'queues' do
|
24
|
+
it 'allows to specify a queue' do
|
25
|
+
class BarJob
|
26
|
+
@queue = 'barqueue'
|
27
|
+
def self.perform; end
|
28
|
+
end
|
29
|
+
|
30
|
+
expect {
|
31
|
+
Rabbithole.enqueue(BarJob)
|
32
|
+
}.to change {Rabbithole::Connection.queue('barqueue').message_count}.by 1
|
33
|
+
Rabbithole::Connection.queue('barqueue').pop
|
34
|
+
|
35
|
+
expect {
|
36
|
+
Rabbithole.enqueue(BarJob)
|
37
|
+
}.not_to change {Rabbithole::Connection.default_queue}
|
38
|
+
Rabbithole::Connection.queue('barqueue').pop
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
if RUBY_VERSION =~ /^(1\.9|2)/
|
2
|
+
require 'coveralls'
|
3
|
+
Coveralls.wear!
|
4
|
+
end
|
5
|
+
|
6
|
+
require 'rspec'
|
7
|
+
require 'pry'
|
8
|
+
|
9
|
+
ROOT = Pathname.new(__FILE__).dirname.join('..')
|
10
|
+
require ROOT.join('lib', 'rabbithole')
|
11
|
+
require 'net/http'
|
12
|
+
|
13
|
+
Dir[ROOT.join("spec/support/**/*.rb")].each {|f| require f}
|
14
|
+
|
15
|
+
RABBITCTL_COMMAND = ENV['TRAVIS'] ? 'sudo rabbitmqctl' : 'rabbitmqctl'
|
16
|
+
|
17
|
+
Thread.abort_on_exception = true
|
18
|
+
|
19
|
+
RSpec.configure do |config|
|
20
|
+
config.mock_with :rspec
|
21
|
+
|
22
|
+
config.before :suite do
|
23
|
+
# Create test vhost
|
24
|
+
%x{
|
25
|
+
#{RABBITCTL_COMMAND} add_vhost #{Rabbithole::Connection::Settings.vhost}
|
26
|
+
#{RABBITCTL_COMMAND} add_user #{Rabbithole::Connection::Settings.user} #{Rabbithole::Connection::Settings.password}
|
27
|
+
#{RABBITCTL_COMMAND} set_permissions -p #{Rabbithole::Connection::Settings.vhost} #{Rabbithole::Connection::Settings.user} ".*" ".*" ".*"
|
28
|
+
}
|
29
|
+
unless ENV['TRAVIS']
|
30
|
+
%x{#{RABBITCTL_COMMAND} set_permissions -p #{Rabbithole::Connection::Settings.vhost} guest ".*" ".*" ".*"}
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
config.after :suite do
|
35
|
+
%x{
|
36
|
+
#{RABBITCTL_COMMAND} delete_vhost #{Rabbithole::Connection::Settings.vhost}
|
37
|
+
#{RABBITCTL_COMMAND} delete_user #{Rabbithole::Connection::Settings.user}
|
38
|
+
}
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class Rails
|
2
|
+
def self.env
|
3
|
+
'test'
|
4
|
+
end
|
5
|
+
|
6
|
+
def self.root
|
7
|
+
Pathname.new(__FILE__).dirname.join('..', 'fixtures')
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.application
|
11
|
+
RailsFakeApp.new
|
12
|
+
end
|
13
|
+
|
14
|
+
class RailsFakeApp
|
15
|
+
def self.parent_name
|
16
|
+
'rails_fake_app'
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
metadata
ADDED
@@ -0,0 +1,138 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rabbithole
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Michael Schaefermeyer
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-11-08 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bunny
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.0.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 1.0.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: settingslogic
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 2.0.9
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 2.0.9
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: msgpack
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ~>
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0.5'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0.5'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: thor
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0.18'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ~>
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0.18'
|
69
|
+
description: Rabbithole encapsulate logic to trigger and run asyncronous jobs using
|
70
|
+
RabbitMQ
|
71
|
+
email:
|
72
|
+
- mschaefermeyer@bleacherreport.com
|
73
|
+
executables:
|
74
|
+
- rabbithole
|
75
|
+
extensions: []
|
76
|
+
extra_rdoc_files: []
|
77
|
+
files:
|
78
|
+
- .coveralls.yml
|
79
|
+
- .gitignore
|
80
|
+
- .rspec
|
81
|
+
- .travis.yml
|
82
|
+
- Gemfile
|
83
|
+
- Guardfile
|
84
|
+
- LICENSE.txt
|
85
|
+
- README.md
|
86
|
+
- Rakefile
|
87
|
+
- bin/rabbithole
|
88
|
+
- lib/rabbithole.rb
|
89
|
+
- lib/rabbithole/cli.rb
|
90
|
+
- lib/rabbithole/connection.rb
|
91
|
+
- lib/rabbithole/error_handler.rb
|
92
|
+
- lib/rabbithole/error_handlers/null_handler.rb
|
93
|
+
- lib/rabbithole/error_handlers/raise_handler.rb
|
94
|
+
- lib/rabbithole/errors.rb
|
95
|
+
- lib/rabbithole/version.rb
|
96
|
+
- lib/rabbithole/worker.rb
|
97
|
+
- rabbithole.gemspec
|
98
|
+
- spec/fixtures/config/amqp.yml
|
99
|
+
- spec/lib/rabbithole/connection_spec.rb
|
100
|
+
- spec/lib/rabbithole/error_handlers/null_handler_spec.rb
|
101
|
+
- spec/lib/rabbithole/error_handlers/raise_handler_spec.rb
|
102
|
+
- spec/lib/rabbithole/worker_spec.rb
|
103
|
+
- spec/lib/rabbithole_spec.rb
|
104
|
+
- spec/spec_helper.rb
|
105
|
+
- spec/support/fake_rails.rb
|
106
|
+
homepage: ''
|
107
|
+
licenses:
|
108
|
+
- MIT
|
109
|
+
metadata: {}
|
110
|
+
post_install_message:
|
111
|
+
rdoc_options: []
|
112
|
+
require_paths:
|
113
|
+
- lib
|
114
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
115
|
+
requirements:
|
116
|
+
- - '>='
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: '0'
|
119
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
120
|
+
requirements:
|
121
|
+
- - '>='
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
version: '0'
|
124
|
+
requirements: []
|
125
|
+
rubyforge_project:
|
126
|
+
rubygems_version: 2.0.3
|
127
|
+
signing_key:
|
128
|
+
specification_version: 4
|
129
|
+
summary: Rabbithole encapsulate logic to trigger and run asyncronous jobs using RabbitMQ
|
130
|
+
test_files:
|
131
|
+
- spec/fixtures/config/amqp.yml
|
132
|
+
- spec/lib/rabbithole/connection_spec.rb
|
133
|
+
- spec/lib/rabbithole/error_handlers/null_handler_spec.rb
|
134
|
+
- spec/lib/rabbithole/error_handlers/raise_handler_spec.rb
|
135
|
+
- spec/lib/rabbithole/worker_spec.rb
|
136
|
+
- spec/lib/rabbithole_spec.rb
|
137
|
+
- spec/spec_helper.rb
|
138
|
+
- spec/support/fake_rails.rb
|