micro_q 0.6.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. data/.gitignore +13 -0
  2. data/.rspec +2 -0
  3. data/.travis.yml +16 -0
  4. data/Gemfile +2 -0
  5. data/LICENSE +22 -0
  6. data/README.md +27 -0
  7. data/Rakefile +6 -0
  8. data/lib/micro_q/config.rb +27 -0
  9. data/lib/micro_q/manager/default.rb +38 -0
  10. data/lib/micro_q/manager.rb +1 -0
  11. data/lib/micro_q/methods/active_record.rb +21 -0
  12. data/lib/micro_q/methods/class.rb +13 -0
  13. data/lib/micro_q/methods/instance.rb +13 -0
  14. data/lib/micro_q/methods.rb +25 -0
  15. data/lib/micro_q/middleware/chain.rb +102 -0
  16. data/lib/micro_q/middleware/server/retry.rb +32 -0
  17. data/lib/micro_q/middleware.rb +1 -0
  18. data/lib/micro_q/proxies/base.rb +49 -0
  19. data/lib/micro_q/proxies/class.rb +6 -0
  20. data/lib/micro_q/proxies/instance.rb +9 -0
  21. data/lib/micro_q/proxies.rb +3 -0
  22. data/lib/micro_q/queue/default.rb +90 -0
  23. data/lib/micro_q/queue.rb +1 -0
  24. data/lib/micro_q/util.rb +29 -0
  25. data/lib/micro_q/version.rb +7 -0
  26. data/lib/micro_q/worker/standard.rb +40 -0
  27. data/lib/micro_q/worker.rb +1 -0
  28. data/lib/micro_q.rb +46 -0
  29. data/micro_q.gemspec +27 -0
  30. data/spec/helpers/methods_examples.rb +45 -0
  31. data/spec/lib/config_spec.rb +47 -0
  32. data/spec/lib/manager/default_spec.rb +69 -0
  33. data/spec/lib/methods/active_record_spec.rb +67 -0
  34. data/spec/lib/methods/class_spec.rb +61 -0
  35. data/spec/lib/methods/instance_spec.rb +55 -0
  36. data/spec/lib/micro_q_spec.rb +80 -0
  37. data/spec/lib/middleware/chain_spec.rb +266 -0
  38. data/spec/lib/middleware/server/retry_spec.rb +87 -0
  39. data/spec/lib/proxies/base_spec.rb +184 -0
  40. data/spec/lib/proxies/class_spec.rb +15 -0
  41. data/spec/lib/proxies/instance_spec.rb +41 -0
  42. data/spec/lib/queue/default_spec.rb +158 -0
  43. data/spec/lib/util_spec.rb +51 -0
  44. data/spec/lib/worker/standard_spec.rb +88 -0
  45. data/spec/spec_helper.rb +59 -0
  46. metadata +219 -0
@@ -0,0 +1,158 @@
1
+ require 'spec_helper'
2
+
3
+ describe MicroQ::Queue::Default do
4
+ describe '#entries' do
5
+ it 'should be empty' do
6
+ subject.entries.should == []
7
+ end
8
+ end
9
+
10
+ describe '#later' do
11
+ it 'should be empty' do
12
+ subject.later.should == []
13
+ end
14
+ end
15
+
16
+ describe '#push' do
17
+ let(:item) { { 'class' => 'MyWorker', 'args' => [] } }
18
+
19
+ it 'should add to the entries' do
20
+ subject.push(item)
21
+
22
+ subject.entries.should include(item)
23
+ end
24
+
25
+ it 'should duplicate the item' do
26
+ subject.push(item)
27
+
28
+ before = item.dup
29
+ subject.entries.should include(before)
30
+
31
+ item[:key] = 'new-value'
32
+ subject.entries.should_not include(item)
33
+ subject.entries.should include(before)
34
+ end
35
+
36
+ describe 'when given the "when" key' do
37
+ let(:worker) { [item, { 'when' => (Time.now + 100).to_i }] }
38
+
39
+ it 'should add to the later' do
40
+ subject.push(*worker)
41
+
42
+ subject.later.should include(
43
+ 'when' => (Time.now + 100).to_i,
44
+ 'worker' => item
45
+ )
46
+ end
47
+
48
+ it 'should not be in the entries' do
49
+ subject.push(*worker)
50
+
51
+ subject.entries.should == []
52
+ end
53
+ end
54
+
55
+ describe 'when given the symbol :when key' do
56
+ let(:worker) { [item, { :when => (Time.now + 100).to_i }] }
57
+
58
+ it 'should add to the later' do
59
+ subject.push(*worker)
60
+
61
+ subject.later.should include(
62
+ 'when' => (Time.now + 100).to_i,
63
+ 'worker' => item
64
+ )
65
+ end
66
+
67
+ it 'should not be in the entries' do
68
+ subject.push(*worker)
69
+
70
+ subject.entries.should == []
71
+ end
72
+ end
73
+ end
74
+
75
+ describe '#dequeue' do
76
+ let(:item) { { 'class' => 'MyWorker', 'args' => [] } }
77
+
78
+ class MyWorker
79
+ def perform(*)
80
+ end
81
+ end
82
+
83
+ describe 'when there are entries' do
84
+ before do
85
+ subject.push(item)
86
+ end
87
+
88
+ it 'should return the item' do
89
+ subject.dequeue.should == [item]
90
+ end
91
+
92
+ it 'should remove the item from the list' do
93
+ subject.dequeue
94
+
95
+ subject.entries.should_not include(item)
96
+ end
97
+ end
98
+
99
+ describe 'when there are items to be processed later' do
100
+ before do
101
+ subject.push(item, 'when' => (Time.now + 5).to_i)
102
+ end
103
+
104
+ it 'should not return the item' do
105
+ subject.dequeue.should == []
106
+ end
107
+
108
+ it 'should not remove the item' do
109
+ subject.dequeue
110
+
111
+ subject.later.should == ['when' => (Time.now + 5).to_i, 'worker' => item]
112
+ end
113
+
114
+ describe 'when the item is in the past' do
115
+ before do
116
+ subject.later.first['when'] = (Time.now - 2).to_i
117
+ end
118
+
119
+ it 'should return the item' do
120
+ subject.dequeue.should == [item]
121
+ end
122
+
123
+ it 'should remove the item from the list' do
124
+ subject.dequeue
125
+
126
+ subject.later.should == []
127
+ end
128
+ end
129
+ end
130
+
131
+ describe 'when there are many items' do
132
+ let(:later_item) { [item.dup.tap {|it| it['args'] = %w(special) }, 'when' => (Time.now + 5).to_i] }
133
+ let(:items) do
134
+ 5.times.collect {|i|
135
+ item.dup.tap {|it| it['args'] = [i]}
136
+ }
137
+ end
138
+
139
+ before do
140
+ items.first(4).each {|item| subject.push(item) }
141
+ subject.push(items.last, 'when' => (Time.now - 2).to_i)
142
+
143
+ subject.push(*later_item)
144
+ end
145
+
146
+ it 'should return all the available items' do
147
+ subject.dequeue.sort {|x, y| x['args'][0] <=> y['args'][0] }.should == items
148
+ end
149
+
150
+ it 'should remove the items' do
151
+ subject.dequeue
152
+
153
+ subject.entries.should == []
154
+ subject.later.should == [later_item[1].merge('worker' => later_item[0])]
155
+ end
156
+ end
157
+ end
158
+ end
@@ -0,0 +1,51 @@
1
+ require 'spec_helper'
2
+
3
+ describe MicroQ::Util do
4
+ describe '.constantize' do
5
+ it 'should work form simple class names' do
6
+ MicroQ::Util.constantize('MicroQ').should == MicroQ
7
+ end
8
+
9
+ it 'should work for complex class names' do
10
+ MicroQ::Util.constantize('MicroQ::Util').should == MicroQ::Util
11
+ end
12
+
13
+ it 'should work for "root" complex class names' do
14
+ MicroQ::Util.constantize('::MicroQ::Util').should == MicroQ::Util
15
+ end
16
+
17
+ describe 'when the name is not defined' do
18
+ it 'should return nil' do
19
+ MicroQ::Util.constantize('AnUndefinedClassName').should == nil
20
+ end
21
+ end
22
+ end
23
+
24
+ describe 'stringify_keys' do
25
+ def str(thing)
26
+ MicroQ::Util.stringify_keys(thing)
27
+ end
28
+
29
+ it 'should change to strings' do
30
+ str(:key => 'value').should == {'key' => 'value'}
31
+ end
32
+
33
+ it 'should work for mixed keys' do
34
+ str(:key => 'value', 4 => '2', 'string' => 'same').should == {
35
+ 'key' => 'value',
36
+ '4' => '2',
37
+ 'string' => 'same'
38
+ }
39
+ end
40
+
41
+ it 'should deep stringify' do
42
+ str(:top => { :key => 'value', 4 => '2', 'string' => 'same' }).should == {
43
+ 'top' => {
44
+ 'key' => 'value',
45
+ '4' => '2',
46
+ 'string' => 'same'
47
+ }
48
+ }
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,88 @@
1
+ require 'spec_helper'
2
+
3
+ describe MicroQ::Worker::Standard do
4
+ let(:worker) { {'class' => 'MyWorker', 'args' => [1, 'value']} }
5
+ let(:other_worker) { {'class' => 'MyWorker', 'method' => 'process', 'args' => [2, 'other-value']} }
6
+
7
+ class MyWorker
8
+ def self.seed(*args); "SEEDED #{args.inspect}" end
9
+ def ar_perform(*args);"AR PERFORM! #{args.inspect}" end
10
+ def perform(*args); "PERFORMED! #{args.inspect}" end
11
+ def process(*args); "PROCESSED! #{args.inspect}" end
12
+ end
13
+
14
+ describe '#perform' do
15
+ def perform(item)
16
+ subject.perform(item)
17
+ end
18
+
19
+ it 'should call the method' do
20
+ perform(worker).should == 'PERFORMED! [1, "value"]'
21
+ perform(other_worker).should == 'PROCESSED! [2, "other-value"]'
22
+ end
23
+
24
+ it 'should process the middleware chain' do
25
+ MicroQ.middleware.server.should_receive(:call) do |w, payload|
26
+ w.class.should == MyWorker
27
+
28
+ payload['class'].should == 'MyWorker'
29
+ payload['args'].should == [1, 'value']
30
+ end
31
+
32
+ perform(worker)
33
+ end
34
+
35
+ it 'should process the middleware chain for both workers' do
36
+ MicroQ.middleware.server.should_receive(:call) do |w, payload|
37
+ w.class.should == MyWorker
38
+
39
+ payload['class'].should == 'MyWorker'
40
+ payload['args'].should == [2, 'other-value']
41
+ end
42
+
43
+ perform(other_worker)
44
+ end
45
+
46
+ describe 'when using the class loader' do
47
+ let(:class_worker) { {'class' => 'MyWorker', 'method' => 'seed', 'args' => [3, 45], 'loader' => {}} }
48
+
49
+ it 'should not create an instance' do
50
+ MyWorker.should_not_receive(:new)
51
+
52
+ perform(class_worker)
53
+ end
54
+
55
+ it 'should call the method' do
56
+ perform(class_worker).should == "SEEDED [3, 45]"
57
+ end
58
+ end
59
+
60
+ describe 'when the model has a custom \'loader\'' do
61
+ let(:ar_worker) { {'class' => 'MyWorker', 'method' => 'ar_perform', 'args' => [1, 2], 'loader' => {'method' => 'find', 'args' => [456]}} }
62
+
63
+ before do
64
+ @model = mock("Model", :ar_perform => nil)
65
+ MyWorker.stub(:find).with(456).and_return(@model)
66
+ end
67
+
68
+ it 'should load the class' do
69
+ MyWorker.should_receive(:find).with(456).and_return(@model)
70
+
71
+ perform(ar_worker)
72
+ end
73
+
74
+ it 'should call the method a' do
75
+ @model.should_receive(:ar_perform).with(1, 2)
76
+
77
+ perform(ar_worker)
78
+ end
79
+
80
+ it 'should call the method b' do
81
+ worker = MyWorker.new
82
+ MyWorker.stub(:find).with(456).and_return(worker)
83
+
84
+ perform(ar_worker).should == 'AR PERFORM! [1, 2]'
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,59 @@
1
+ require 'micro_q'
2
+ require 'time'
3
+ require 'timecop'
4
+ require 'celluloid'
5
+
6
+ require 'helpers/methods_examples'
7
+
8
+ Celluloid.logger = nil
9
+
10
+ RSpec.configure do |config|
11
+ config.treat_symbols_as_metadata_keys_with_true_values = true
12
+ config.run_all_when_everything_filtered = true
13
+
14
+ config.order = 'default'
15
+
16
+ config.before :each do
17
+ MicroQ.send :clear
18
+ end
19
+
20
+ config.before :each, :active_record => true do
21
+ require 'active_record'
22
+ require 'sqlite3' # https://github.com/luislavena/sqlite3-ruby
23
+
24
+ db_name = ENV['TEST_DATABASE'] || 'micro_q-test.db'
25
+
26
+ (@_db = SQLite3::Database.new(db_name)).
27
+ execute(<<-SQL)
28
+ create table if not exists repositories (
29
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
30
+ name varchar(255)
31
+ );
32
+ SQL
33
+
34
+ # ** Transactional fixtures. **
35
+ @_db.transaction
36
+
37
+ ActiveRecord::Base.establish_connection(
38
+ :adapter => 'sqlite3',
39
+ :database => db_name
40
+ )
41
+ end
42
+
43
+ config.after :each, :active_record => true do
44
+ @_db.rollback
45
+ end
46
+
47
+ config.before :each, :middleware => true do
48
+ class WorkerClass; end
49
+
50
+ @worker = WorkerClass.new
51
+ @payload = { 'class' => 'WorkerClass', 'args' => [1, 2]}
52
+ end
53
+ end
54
+
55
+ def safe(method, *args)
56
+ send(method, *args)
57
+ rescue Exception
58
+ nil
59
+ end
metadata ADDED
@@ -0,0 +1,219 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: micro_q
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.6.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Brian Norton
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-02-04 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: celluloid
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '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'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rake
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: rspec
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
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
+ - !ruby/object:Gem::Dependency
63
+ name: timecop
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: psych
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ - !ruby/object:Gem::Dependency
95
+ name: activerecord
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>'
100
+ - !ruby/object:Gem::Version
101
+ version: 3.2.0
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>'
108
+ - !ruby/object:Gem::Version
109
+ version: 3.2.0
110
+ - !ruby/object:Gem::Dependency
111
+ name: sqlite3-ruby
112
+ requirement: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ! '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ! '>='
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ description: ''
127
+ email:
128
+ - brian.nort@gmail.com
129
+ executables: []
130
+ extensions: []
131
+ extra_rdoc_files: []
132
+ files:
133
+ - .gitignore
134
+ - .rspec
135
+ - .travis.yml
136
+ - Gemfile
137
+ - LICENSE
138
+ - README.md
139
+ - Rakefile
140
+ - lib/micro_q.rb
141
+ - lib/micro_q/config.rb
142
+ - lib/micro_q/manager.rb
143
+ - lib/micro_q/manager/default.rb
144
+ - lib/micro_q/methods.rb
145
+ - lib/micro_q/methods/active_record.rb
146
+ - lib/micro_q/methods/class.rb
147
+ - lib/micro_q/methods/instance.rb
148
+ - lib/micro_q/middleware.rb
149
+ - lib/micro_q/middleware/chain.rb
150
+ - lib/micro_q/middleware/server/retry.rb
151
+ - lib/micro_q/proxies.rb
152
+ - lib/micro_q/proxies/base.rb
153
+ - lib/micro_q/proxies/class.rb
154
+ - lib/micro_q/proxies/instance.rb
155
+ - lib/micro_q/queue.rb
156
+ - lib/micro_q/queue/default.rb
157
+ - lib/micro_q/util.rb
158
+ - lib/micro_q/version.rb
159
+ - lib/micro_q/worker.rb
160
+ - lib/micro_q/worker/standard.rb
161
+ - micro_q.gemspec
162
+ - spec/helpers/methods_examples.rb
163
+ - spec/lib/config_spec.rb
164
+ - spec/lib/manager/default_spec.rb
165
+ - spec/lib/methods/active_record_spec.rb
166
+ - spec/lib/methods/class_spec.rb
167
+ - spec/lib/methods/instance_spec.rb
168
+ - spec/lib/micro_q_spec.rb
169
+ - spec/lib/middleware/chain_spec.rb
170
+ - spec/lib/middleware/server/retry_spec.rb
171
+ - spec/lib/proxies/base_spec.rb
172
+ - spec/lib/proxies/class_spec.rb
173
+ - spec/lib/proxies/instance_spec.rb
174
+ - spec/lib/queue/default_spec.rb
175
+ - spec/lib/util_spec.rb
176
+ - spec/lib/worker/standard_spec.rb
177
+ - spec/spec_helper.rb
178
+ homepage: http://github.com/bnorton/micro-q
179
+ licenses: []
180
+ post_install_message:
181
+ rdoc_options: []
182
+ require_paths:
183
+ - lib
184
+ required_ruby_version: !ruby/object:Gem::Requirement
185
+ none: false
186
+ requirements:
187
+ - - ! '>='
188
+ - !ruby/object:Gem::Version
189
+ version: '0'
190
+ required_rubygems_version: !ruby/object:Gem::Requirement
191
+ none: false
192
+ requirements:
193
+ - - ! '>='
194
+ - !ruby/object:Gem::Version
195
+ version: '0'
196
+ requirements: []
197
+ rubyforge_project:
198
+ rubygems_version: 1.8.25
199
+ signing_key:
200
+ specification_version: 3
201
+ summary: ''
202
+ test_files:
203
+ - spec/helpers/methods_examples.rb
204
+ - spec/lib/config_spec.rb
205
+ - spec/lib/manager/default_spec.rb
206
+ - spec/lib/methods/active_record_spec.rb
207
+ - spec/lib/methods/class_spec.rb
208
+ - spec/lib/methods/instance_spec.rb
209
+ - spec/lib/micro_q_spec.rb
210
+ - spec/lib/middleware/chain_spec.rb
211
+ - spec/lib/middleware/server/retry_spec.rb
212
+ - spec/lib/proxies/base_spec.rb
213
+ - spec/lib/proxies/class_spec.rb
214
+ - spec/lib/proxies/instance_spec.rb
215
+ - spec/lib/queue/default_spec.rb
216
+ - spec/lib/util_spec.rb
217
+ - spec/lib/worker/standard_spec.rb
218
+ - spec/spec_helper.rb
219
+ has_rdoc: