queueing_rabbit 0.1.0.rc1

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