queueing_rabbit 0.1.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. data/.gitignore +17 -0
  2. data/.rvmrc +48 -0
  3. data/Gemfile +9 -0
  4. data/LICENSE +22 -0
  5. data/README.md +38 -0
  6. data/Rakefile +5 -0
  7. data/lib/queueing_rabbit/callbacks.rb +31 -0
  8. data/lib/queueing_rabbit/client/amqp.rb +148 -0
  9. data/lib/queueing_rabbit/client/bunny.rb +62 -0
  10. data/lib/queueing_rabbit/client/callbacks.rb +14 -0
  11. data/lib/queueing_rabbit/configuration.rb +24 -0
  12. data/lib/queueing_rabbit/job.rb +32 -0
  13. data/lib/queueing_rabbit/logging.rb +17 -0
  14. data/lib/queueing_rabbit/serializer.rb +19 -0
  15. data/lib/queueing_rabbit/tasks.rb +37 -0
  16. data/lib/queueing_rabbit/version.rb +3 -0
  17. data/lib/queueing_rabbit/worker.rb +96 -0
  18. data/lib/queueing_rabbit.rb +67 -0
  19. data/lib/tasks/queueing_rabbit.rake +2 -0
  20. data/queueing_rabbit.gemspec +49 -0
  21. data/spec/integration/asynchronous_publishing_and_consuming_spec.rb +62 -0
  22. data/spec/integration/jobs/print_line_job.rb +17 -0
  23. data/spec/integration/synchronous_publishing_and_asynchronous_consuming_spec.rb +39 -0
  24. data/spec/integration/synchronous_publishing_spec.rb +24 -0
  25. data/spec/spec_helper.rb +26 -0
  26. data/spec/support/shared_contexts.rb +17 -0
  27. data/spec/support/shared_examples.rb +60 -0
  28. data/spec/unit/queueing_rabbit/callbacks_spec.rb +53 -0
  29. data/spec/unit/queueing_rabbit/client/amqp_spec.rb +193 -0
  30. data/spec/unit/queueing_rabbit/client/bunny_spec.rb +68 -0
  31. data/spec/unit/queueing_rabbit/client/callbacks_spec.rb +22 -0
  32. data/spec/unit/queueing_rabbit/configuration_spec.rb +19 -0
  33. data/spec/unit/queueing_rabbit/job_spec.rb +23 -0
  34. data/spec/unit/queueing_rabbit/logging_spec.rb +9 -0
  35. data/spec/unit/queueing_rabbit/serializer_spec.rb +26 -0
  36. data/spec/unit/queueing_rabbit/worker_spec.rb +133 -0
  37. data/spec/unit/queueing_rabbit_spec.rb +105 -0
  38. metadata +168 -0
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+
3
+ describe QueueingRabbit::Client::Callbacks do
4
+ let!(:klass) { Class.new { extend QueueingRabbit::Client::Callbacks } }
5
+
6
+ subject { klass }
7
+
8
+ it { should respond_to(:define_callback).with(1).argument }
9
+ it { should respond_to(:callback).with(1).argument }
10
+
11
+ context 'when a callback is being defined' do
12
+ let(:code_block) { Proc.new {} }
13
+
14
+ before do
15
+ subject.define_callback(:on_some_event, &code_block)
16
+ end
17
+
18
+ it 'saves a provided code block as a callback' do
19
+ subject.callback(:on_some_event).should == code_block
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+
3
+ describe QueueingRabbit::Configuration do
4
+ subject { Class.new { extend QueueingRabbit::Configuration} }
5
+
6
+ it { should respond_to(:amqp_uri) }
7
+ it { should respond_to(:amqp_exchange_name) }
8
+ it { should respond_to(:amqp_exchange_options) }
9
+
10
+ its(:tcp_timeout) { should == 1 }
11
+ its(:heartbeat) { should == 10 }
12
+ its(:default_client) { should == QueueingRabbit::Client::Bunny }
13
+
14
+ describe "#configure" do
15
+ it "yields itself to the block" do
16
+ subject.configure { |obj| obj.should == subject }
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+
3
+ describe QueueingRabbit::AbstractJob do
4
+ subject { QueueingRabbit::AbstractJob }
5
+
6
+ it { should respond_to(:queue).with(2).arguments }
7
+ it { should respond_to(:queue_name) }
8
+ it { should respond_to(:queue_options) }
9
+ it { should respond_to(:channel_options) }
10
+ it { should respond_to(:channel).with(1).argument }
11
+
12
+ its(:queue_name) { should == 'AbstractJob' }
13
+
14
+ describe ".queue_size" do
15
+ let(:size) { mock }
16
+
17
+ before do
18
+ QueueingRabbit.should_receive(:queue_size).with(subject).and_return(size)
19
+ end
20
+
21
+ its(:queue_size) { should == size }
22
+ end
23
+ end
@@ -0,0 +1,9 @@
1
+ require 'spec_helper'
2
+
3
+ describe QueueingRabbit::Logging do
4
+ subject { Class.new { extend QueueingRabbit::Logging } }
5
+
6
+ %w[fatal error warn info debug].each do |level|
7
+ it { should respond_to(level).with(1).argument }
8
+ end
9
+ end
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+
3
+ describe QueueingRabbit::Serializer do
4
+ subject { Class.new { extend QueueingRabbit::Serializer } }
5
+ let(:args) { {:a => 1, :b => 2, :c => 3} }
6
+
7
+ describe ".serialize" do
8
+ it "serializes arguments to JSON" do
9
+ subject.serialize(args).should == JSON.dump(args)
10
+ end
11
+ end
12
+
13
+ describe ".deserialize" do
14
+ it "deserializes arguments from JSON to symbolized hash" do
15
+ subject.deserialize(JSON.dump(args)).should == args
16
+ end
17
+ end
18
+
19
+ describe ".symbolize_keys" do
20
+ let(:stringified_args) { { "a" => 1, "b" => 2, "c" => 3 } }
21
+
22
+ it "symbolizes keys of provided Hash" do
23
+ subject.send(:symbolize_keys, stringified_args).should == args
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,133 @@
1
+ require 'spec_helper'
2
+
3
+ describe QueueingRabbit::Worker do
4
+ include_context "StringIO logger"
5
+
6
+ subject { QueueingRabbit::Worker }
7
+ let!(:job) {
8
+ class QueueingRabbitTestJob < QueueingRabbit::AbstractJob
9
+ def self.perform(arguments = {}); end
10
+ end
11
+ }
12
+ let(:creation) {
13
+ Proc.new { QueueingRabbit::Worker.new('QueueingRabbitTestJob') }
14
+ }
15
+ let(:worker) {
16
+ creation.call
17
+ }
18
+
19
+ after(:each) do
20
+ QueueingRabbit.client = QueueingRabbit::Client::Bunny
21
+ end
22
+
23
+ context 'initialization' do
24
+ context 'when no jobs are provided' do
25
+ before do
26
+ subject.any_instance.should_receive(:fatal)
27
+ end
28
+
29
+ it 'raises JobNotPresentError' do
30
+ expect { subject.new() }
31
+ .to raise_error(QueueingRabbit::JobNotPresentError)
32
+ end
33
+ end
34
+
35
+ context 'when nonexistent job is provided' do
36
+ let(:nonexistent_class_name) { 'SomeNonexistentClassName' }
37
+
38
+ before do
39
+ subject.any_instance.should_receive(:fatal)
40
+ end
41
+
42
+ it 'raises JobNotFoundError' do
43
+ expect { subject.new(nonexistent_class_name) }
44
+ .to raise_error(QueueingRabbit::JobNotFoundError)
45
+ end
46
+ end
47
+
48
+ context 'when valid job is provided' do
49
+ subject { worker }
50
+
51
+ it { should be }
52
+ it { should respond_to(:jobs) }
53
+ it 'changes used client to asynchronous' do
54
+ expect { creation.call }.to change { QueueingRabbit.client.to_s }
55
+ .from(QueueingRabbit::Client::Bunny.to_s)
56
+ .to(QueueingRabbit::Client::AMQP.to_s)
57
+ end
58
+ end
59
+ end
60
+
61
+ context 'instance methods' do
62
+ let(:connection) { mock }
63
+ let(:channel) { mock }
64
+ let(:arguments) { mock }
65
+
66
+ subject { worker }
67
+
68
+ describe '#work' do
69
+ before do
70
+ QueueingRabbit.should_receive(:connection).and_return(connection)
71
+ connection.should_receive(:open_channel).and_yield(channel, nil)
72
+ connection.should_receive(:listen_queue).and_yield(arguments)
73
+ end
74
+
75
+ it 'listens to queues specified by jobs' do
76
+ subject.work
77
+ end
78
+
79
+ context "logging" do
80
+ before do
81
+ subject.should_receive(:info)
82
+ end
83
+
84
+ it 'writes to the log' do
85
+ subject.work
86
+ end
87
+ end
88
+
89
+ describe '#work!' do
90
+ before do
91
+ QueueingRabbit::Client::AMQP
92
+ .should_receive(:join_event_machine_thread)
93
+ end
94
+
95
+ it 'runs #work and joins the eventmachine thread' do
96
+ subject.work!
97
+ end
98
+ end
99
+ end
100
+
101
+ describe "#use_pidfile" do
102
+ let(:file_name) { mock }
103
+ let(:file) { mock }
104
+
105
+ before do
106
+ File.should_receive(:open).with(file_name, 'w').and_yield(file)
107
+ file.should_receive(:<<).with(Process.pid)
108
+ end
109
+
110
+ it 'writes pid to a file' do
111
+ subject.use_pidfile(file_name)
112
+ end
113
+ end
114
+
115
+ describe "#remove_pidfile" do
116
+ let(:file_name) { mock }
117
+
118
+ before do
119
+ subject.instance_variable_set(:@pidfile, file_name)
120
+ File.should_receive(:exists?).and_return(true)
121
+ File.should_receive(:delete).with(file_name)
122
+ end
123
+
124
+ it 'removes previously created pidfile' do
125
+ subject.remove_pidfile
126
+ end
127
+ end
128
+
129
+ describe "#pid" do
130
+ its(:pid) { should == Process.pid }
131
+ end
132
+ end
133
+ end
@@ -0,0 +1,105 @@
1
+ require 'spec_helper'
2
+
3
+ describe QueueingRabbit do
4
+ include_context "StringIO logger"
5
+
6
+ let(:connection) { mock }
7
+ let(:queue_name) { mock }
8
+ let(:queue_options) { { :durable => true} }
9
+ let(:channel) { mock }
10
+ let(:channel_options) { { :prefetch => 1, :auto_recovery => true } }
11
+ let(:job) do
12
+ qname, qopts, copts = queue_name, queue_options, channel_options
13
+ Class.new do
14
+ extend QueueingRabbit::Job
15
+ queue qname, qopts
16
+ channel copts
17
+ end
18
+ end
19
+
20
+ before(:each) { subject.drop_connection }
21
+
22
+ it { should respond_to(:logger) }
23
+ it { should respond_to(:client) }
24
+
25
+ its(:logger) { should be_kind_of(Logger) }
26
+ its(:client) { should be(QueueingRabbit::Client::Bunny) }
27
+
28
+ describe ".connect" do
29
+ before do
30
+ subject.client.should_receive(:connect).and_return(connection)
31
+ subject.connect
32
+ end
33
+
34
+ its(:connect) { should == connection }
35
+ its(:connection) { should == connection }
36
+ end
37
+
38
+ describe ".enqueue" do
39
+ let(:arguments) { mock }
40
+
41
+ before do
42
+ subject.instance_variable_set(:@connection, connection)
43
+ connection.should_receive(:open_channel).with(channel_options)
44
+ .and_yield(channel, nil)
45
+ connection.should_receive(:define_queue).with(channel,
46
+ queue_name,
47
+ queue_options)
48
+ connection.should_receive(:enqueue).with(channel,
49
+ queue_name, arguments)
50
+ end
51
+
52
+ it 'returns true when a message was enqueued successfully' do
53
+ subject.enqueue(job, arguments).should be_true
54
+ end
55
+
56
+ context 'logging' do
57
+ before do
58
+ subject.should_receive(:info).and_return(nil)
59
+ end
60
+
61
+ it 'keeps the record of enqueued job at info level' do
62
+ subject.enqueue(job, arguments).should be_true
63
+ end
64
+ end
65
+ end
66
+
67
+ describe ".queue_size" do
68
+ let(:size) { mock }
69
+ let(:queue) { mock }
70
+
71
+ before do
72
+ subject.instance_variable_set(:@connection, connection)
73
+ connection.should_receive(:open_channel).with(channel_options)
74
+ .and_yield(channel, nil)
75
+ connection.should_receive(:define_queue).with(channel,
76
+ queue_name,
77
+ queue_options)
78
+ .and_return(queue)
79
+ connection.should_receive(:queue_size).with(queue).and_return(size)
80
+ end
81
+
82
+ it 'returns queue size for specific job' do
83
+ subject.queue_size(job).should == size
84
+ end
85
+ end
86
+
87
+ describe ".purge_queue" do
88
+ let(:queue) { mock }
89
+
90
+ before do
91
+ subject.instance_variable_set(:@connection, connection)
92
+ connection.should_receive(:open_channel).with(channel_options)
93
+ .and_yield(channel, nil)
94
+ connection.should_receive(:define_queue).with(channel,
95
+ queue_name,
96
+ queue_options)
97
+ .and_return(queue)
98
+ queue.should_receive(:purge).and_return(true)
99
+ end
100
+
101
+ it 'purges messages from the queue' do
102
+ subject.purge_queue(job).should be_true
103
+ end
104
+ end
105
+ end
metadata ADDED
@@ -0,0 +1,168 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: queueing_rabbit
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0.rc1
5
+ prerelease: 6
6
+ platform: ruby
7
+ authors:
8
+ - Artem Chistyakov
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-03-21 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: amqp
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 0.9.0
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: 0.9.0
30
+ - !ruby/object:Gem::Dependency
31
+ name: bunny
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: 0.9.0.pre7
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: 0.9.0.pre7
46
+ - !ruby/object:Gem::Dependency
47
+ name: rake
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ description: ! " QueueingRabbit is a Ruby library providing convenient object-oriented
63
+ syntax\n for managing background jobs using AMQP. All jobs' argumets are serialized\n
64
+ \ to JSON and transfered to jobs using AMQP message payload. The library\n implements
65
+ amqp and bunny gems as adapters making it possible to use\n synchronous publishing
66
+ and asynchronous consuming, which might be useful for\n Rails app running on
67
+ non-EventMachine based application servers (i. e.\n Passenger).\n\n Any Ruby
68
+ class or Module can be transformed into QueueingRabbit's background\n job by
69
+ including QueueingRabbit::Job module. It is also possible to inherit\n your class
70
+ from QueueingRabbit::AbstractJob abstract class.\n\n The library is bundled with
71
+ a Rake task which is capable of starting a\n worker processing a specified list
72
+ of jobs.\n\n To achieve the required simplicity the gem doesn't try to support
73
+ all\n features of AMQP protocol. It uses a restricted subset instead:\n\n *
74
+ Only a single direct exchange is used\n * Every job is consumed using a separate
75
+ channel\n * All jobs are consumed with acknowledgements\n * ACK is only sent
76
+ to the broker if a job was processed successfully\n * Currently all messages
77
+ are published with persistent option\n"
78
+ email:
79
+ - chistyakov.artem@gmail.com
80
+ executables: []
81
+ extensions: []
82
+ extra_rdoc_files:
83
+ - LICENSE
84
+ - README.md
85
+ files:
86
+ - .gitignore
87
+ - .rvmrc
88
+ - Gemfile
89
+ - LICENSE
90
+ - README.md
91
+ - Rakefile
92
+ - lib/queueing_rabbit.rb
93
+ - lib/queueing_rabbit/callbacks.rb
94
+ - lib/queueing_rabbit/client/amqp.rb
95
+ - lib/queueing_rabbit/client/bunny.rb
96
+ - lib/queueing_rabbit/client/callbacks.rb
97
+ - lib/queueing_rabbit/configuration.rb
98
+ - lib/queueing_rabbit/job.rb
99
+ - lib/queueing_rabbit/logging.rb
100
+ - lib/queueing_rabbit/serializer.rb
101
+ - lib/queueing_rabbit/tasks.rb
102
+ - lib/queueing_rabbit/version.rb
103
+ - lib/queueing_rabbit/worker.rb
104
+ - lib/tasks/queueing_rabbit.rake
105
+ - queueing_rabbit.gemspec
106
+ - spec/integration/asynchronous_publishing_and_consuming_spec.rb
107
+ - spec/integration/jobs/print_line_job.rb
108
+ - spec/integration/synchronous_publishing_and_asynchronous_consuming_spec.rb
109
+ - spec/integration/synchronous_publishing_spec.rb
110
+ - spec/spec_helper.rb
111
+ - spec/support/shared_contexts.rb
112
+ - spec/support/shared_examples.rb
113
+ - spec/unit/queueing_rabbit/callbacks_spec.rb
114
+ - spec/unit/queueing_rabbit/client/amqp_spec.rb
115
+ - spec/unit/queueing_rabbit/client/bunny_spec.rb
116
+ - spec/unit/queueing_rabbit/client/callbacks_spec.rb
117
+ - spec/unit/queueing_rabbit/configuration_spec.rb
118
+ - spec/unit/queueing_rabbit/job_spec.rb
119
+ - spec/unit/queueing_rabbit/logging_spec.rb
120
+ - spec/unit/queueing_rabbit/serializer_spec.rb
121
+ - spec/unit/queueing_rabbit/worker_spec.rb
122
+ - spec/unit/queueing_rabbit_spec.rb
123
+ homepage: https://github.com/temochka/queueing_rabbit
124
+ licenses: []
125
+ post_install_message:
126
+ rdoc_options:
127
+ - --charset=UTF-8
128
+ require_paths:
129
+ - lib
130
+ required_ruby_version: !ruby/object:Gem::Requirement
131
+ none: false
132
+ requirements:
133
+ - - ! '>='
134
+ - !ruby/object:Gem::Version
135
+ version: '0'
136
+ segments:
137
+ - 0
138
+ hash: 1045735451665817642
139
+ required_rubygems_version: !ruby/object:Gem::Requirement
140
+ none: false
141
+ requirements:
142
+ - - ! '>'
143
+ - !ruby/object:Gem::Version
144
+ version: 1.3.1
145
+ requirements: []
146
+ rubyforge_project:
147
+ rubygems_version: 1.8.25
148
+ signing_key:
149
+ specification_version: 3
150
+ summary: QueueingRabbit is an AMQP-based queueing system
151
+ test_files:
152
+ - spec/integration/asynchronous_publishing_and_consuming_spec.rb
153
+ - spec/integration/jobs/print_line_job.rb
154
+ - spec/integration/synchronous_publishing_and_asynchronous_consuming_spec.rb
155
+ - spec/integration/synchronous_publishing_spec.rb
156
+ - spec/spec_helper.rb
157
+ - spec/support/shared_contexts.rb
158
+ - spec/support/shared_examples.rb
159
+ - spec/unit/queueing_rabbit/callbacks_spec.rb
160
+ - spec/unit/queueing_rabbit/client/amqp_spec.rb
161
+ - spec/unit/queueing_rabbit/client/bunny_spec.rb
162
+ - spec/unit/queueing_rabbit/client/callbacks_spec.rb
163
+ - spec/unit/queueing_rabbit/configuration_spec.rb
164
+ - spec/unit/queueing_rabbit/job_spec.rb
165
+ - spec/unit/queueing_rabbit/logging_spec.rb
166
+ - spec/unit/queueing_rabbit/serializer_spec.rb
167
+ - spec/unit/queueing_rabbit/worker_spec.rb
168
+ - spec/unit/queueing_rabbit_spec.rb