job_dispatch 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.
Files changed (44) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +19 -0
  3. data/.rspec +1 -0
  4. data/.travis.yml +13 -0
  5. data/Gemfile +20 -0
  6. data/Guardfile +13 -0
  7. data/LICENSE.txt +22 -0
  8. data/README.md +85 -0
  9. data/Rakefile +10 -0
  10. data/bin/job-dispatcher +34 -0
  11. data/bin/job-status +69 -0
  12. data/bin/job-worker +40 -0
  13. data/examples/mongoid-job.rb +43 -0
  14. data/job_dispatch.gemspec +33 -0
  15. data/lib/job_dispatch/broker/command.rb +45 -0
  16. data/lib/job_dispatch/broker/internal_job.rb +32 -0
  17. data/lib/job_dispatch/broker/socket.rb +85 -0
  18. data/lib/job_dispatch/broker.rb +523 -0
  19. data/lib/job_dispatch/client/proxy.rb +34 -0
  20. data/lib/job_dispatch/client/proxy_error.rb +18 -0
  21. data/lib/job_dispatch/client/synchronous_proxy.rb +29 -0
  22. data/lib/job_dispatch/client.rb +49 -0
  23. data/lib/job_dispatch/configuration.rb +7 -0
  24. data/lib/job_dispatch/identity.rb +54 -0
  25. data/lib/job_dispatch/job.rb +44 -0
  26. data/lib/job_dispatch/signaller.rb +30 -0
  27. data/lib/job_dispatch/sockets/enqueue.rb +18 -0
  28. data/lib/job_dispatch/status.rb +79 -0
  29. data/lib/job_dispatch/version.rb +3 -0
  30. data/lib/job_dispatch/worker/item.rb +43 -0
  31. data/lib/job_dispatch/worker/socket.rb +96 -0
  32. data/lib/job_dispatch/worker.rb +120 -0
  33. data/lib/job_dispatch.rb +97 -0
  34. data/spec/factories/jobs.rb +19 -0
  35. data/spec/job_dispatch/broker/socket_spec.rb +53 -0
  36. data/spec/job_dispatch/broker_spec.rb +737 -0
  37. data/spec/job_dispatch/identity_spec.rb +88 -0
  38. data/spec/job_dispatch/job_spec.rb +77 -0
  39. data/spec/job_dispatch/worker/socket_spec.rb +32 -0
  40. data/spec/job_dispatch/worker_spec.rb +24 -0
  41. data/spec/job_dispatch_spec.rb +0 -0
  42. data/spec/spec_helper.rb +23 -0
  43. data/spec/support/test_job.rb +30 -0
  44. metadata +255 -0
@@ -0,0 +1,88 @@
1
+ require 'rspec'
2
+ require 'spec_helper'
3
+
4
+ describe JobDispatch::Identity do
5
+
6
+ context "with a string" do
7
+
8
+ subject { JobDispatch::Identity.new('hello')}
9
+
10
+ it "returns a string" do
11
+ expect(subject.to_s).to eq('hello')
12
+ end
13
+ it "returns a symbol" do
14
+ expect(subject.to_sym).to eq(:hello)
15
+ end
16
+ it "returns hex string" do
17
+ expect(subject.to_hex).to eq('68656c6c6f')
18
+ end
19
+ end
20
+
21
+ context "with a symbol" do
22
+
23
+ subject { JobDispatch::Identity.new(:hello)}
24
+
25
+ it "returns a string" do
26
+ expect(subject.to_s).to eq('hello')
27
+ end
28
+ it "returns a symbol" do
29
+ expect(subject.to_sym).to eq(:hello)
30
+ end
31
+ it "returns hex string" do
32
+ expect(subject.to_hex).to eq('68656c6c6f')
33
+ end
34
+ end
35
+
36
+
37
+ context "with no-printable characters" do
38
+ let(:worker_id) { [0, 0x80, 0, 0x41, 0xB9].pack('c*') }
39
+ subject { JobDispatch::Identity.new(worker_id)}
40
+
41
+ it "returns a string" do
42
+ expect(subject.to_s).to eq(worker_id)
43
+ end
44
+ it "returns a symbol" do
45
+ expect(subject.to_sym).to eq(worker_id.to_sym)
46
+ end
47
+ it "returns hex string" do
48
+ expect(subject.to_hex).to eq('00800041b9')
49
+ end
50
+ end
51
+
52
+ context "testing equality" do
53
+
54
+ context "with same identity" do
55
+ before :each do
56
+ @a = JobDispatch::Identity.new('a')
57
+ @b = JobDispatch::Identity.new('a')
58
+ end
59
+
60
+ it "is equal to another with the same identity" do
61
+ expect(@a == @b).to be_true
62
+ end
63
+
64
+ it "can look up an item from a hash" do
65
+ hash = {}
66
+ hash[@a] = 'hello'
67
+ expect(hash[@b]).to eq('hello')
68
+ end
69
+ end
70
+
71
+ context "with different identity" do
72
+ before :each do
73
+ @a = JobDispatch::Identity.new('a')
74
+ @b = JobDispatch::Identity.new('b')
75
+ end
76
+
77
+ it "is not equal to another with the same identity" do
78
+ expect(@a == @b).to be_false
79
+ end
80
+
81
+ it "can look up an item from a hash" do
82
+ hash = {}
83
+ hash[@a] = 'hello'
84
+ expect(hash[@b]).to be_nil
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,77 @@
1
+ require 'rspec'
2
+ require 'spec_helper'
3
+
4
+ describe JobDispatch::Job do
5
+
6
+ context "succeeded" do
7
+ subject { TestJob.new(1, 'default', JobDispatch::Job::PENDING) }
8
+ before(:each) { subject.succeeded!('result') }
9
+ it "sets the status to COMPLETED" do
10
+ expect(subject.status).to eq(JobDispatch::Job::COMPLETED)
11
+ end
12
+
13
+ it "sets the result" do
14
+ expect(subject.result).to eq('result')
15
+ end
16
+ it "sets completed at" do
17
+ expect(subject.completed_at).to be_within(1.second).of(Time.now)
18
+ end
19
+ end
20
+
21
+ context "failed" do
22
+ subject { TestJob.new(1, 'default', JobDispatch::Job::PENDING) }
23
+ before(:each) { subject.failed!('error message') }
24
+ it "sets the status to FAILED" do
25
+ expect(subject.status).to eq(JobDispatch::Job::FAILED)
26
+ end
27
+
28
+ it "sets the result" do
29
+ expect(subject.result).to eq('error message')
30
+ end
31
+
32
+ it "sets completed at" do
33
+ expect(subject.completed_at).to be_within(1.second).of(Time.now)
34
+ end
35
+
36
+ context "and retryable" do
37
+ before(:each) do
38
+ subject.retry_count = 1
39
+ subject.retry_delay = 10
40
+ subject.failed!('error message')
41
+ end
42
+ it "sets the status to PENDING" do
43
+ expect(subject.status).to eq(JobDispatch::Job::PENDING)
44
+ end
45
+ it "sets completed at" do
46
+ expect(subject.completed_at).to be_within(1.second).of(Time.now)
47
+ end
48
+ it "sets the result" do
49
+ expect(subject.result).to eq('error message')
50
+ end
51
+ it "decrements retry_count" do
52
+ expect(subject.retry_count).to eq(0)
53
+ end
54
+ it "doubles the retry_delay" do
55
+ expect(subject.retry_delay).to eq(20)
56
+ end
57
+ end
58
+
59
+ context "and out of retries" do
60
+ before(:each) do
61
+ subject.retry_count = 0
62
+ subject.retry_delay = 20
63
+ subject.failed!('error message')
64
+ end
65
+ it "sets the status to PENDING" do
66
+ expect(subject.status).to eq(JobDispatch::Job::FAILED)
67
+ end
68
+ it "sets completed at" do
69
+ expect(subject.completed_at).to be_within(1.second).of(Time.now)
70
+ end
71
+ it "sets the result" do
72
+ expect(subject.result).to eq('error message')
73
+ end
74
+ end
75
+ end
76
+
77
+ end
@@ -0,0 +1,32 @@
1
+ require 'rspec'
2
+ require 'spec_helper'
3
+
4
+ describe JobDispatch::Worker::Socket do
5
+
6
+ let(:endpoint) { 'ipc://test' }
7
+ let(:item_class) do
8
+ double('ItemClass')
9
+ end
10
+ subject { JobDispatch::Worker::Socket.new(endpoint, item_class) }
11
+
12
+ context "receiving a message" do
13
+ before :each do
14
+ @item = double('Item')
15
+ @item.stub(:job_id=)
16
+ item_class.stub(:new).and_return(@item)
17
+ end
18
+
19
+ it "creates an item of the right class" do
20
+ item_class.should_receive(:new)
21
+ subject.socket.stub(:recv).and_return(JSON.dump({command:'idle'}))
22
+ expect(subject.read_item).to eq(@item)
23
+ end
24
+
25
+ it "quits when a quit message is received" do
26
+ Process.stub(:exit).and_return(nil)
27
+ Process.should_receive(:exit).with(0)
28
+ subject.socket.stub(:recv).and_return(JSON.dump({command:'quit'}))
29
+ subject.read_item
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,24 @@
1
+ require 'rspec'
2
+ require 'spec_helper'
3
+
4
+ describe JobDispatch::Worker do
5
+
6
+ Item ||= JobDispatch::Worker::Item
7
+ Socket ||= JobDispatch::Worker::Socket
8
+
9
+ context "with custom item class" do
10
+ before :each do
11
+ @klass = double('ItemClass')
12
+ @worker = JobDispatch::Worker.new('ipc://test', item_class: @klass)
13
+ end
14
+ it "initialises the custom item class" do
15
+ expect(@worker.item_class).to eq(@klass)
16
+ end
17
+
18
+ it "sets the custom class on the socket" do
19
+ @worker.connect
20
+ expect(@worker.socket.item_class).to eq(@klass)
21
+ end
22
+ end
23
+
24
+ end
File without changes
@@ -0,0 +1,23 @@
1
+ require 'simplecov'
2
+ SimpleCov.start 'rails'
3
+
4
+ require 'job_dispatch'
5
+
6
+ # Requires supporting ruby files with custom matchers and macros, etc,
7
+ # in spec/support/ and its subdirectories.
8
+ Dir["spec/support/**/*.rb"].each { |f| load f }
9
+
10
+ require 'factory_girl'
11
+ Dir["spec/factories/**/*.rb"].each { |f| load f }
12
+
13
+ require 'timecop'
14
+
15
+
16
+ RSpec.configure do |config|
17
+
18
+ # Run specs in random order to surface order dependencies. If you find an
19
+ # order dependency and want to debug it, you can fix the order by providing
20
+ # the seed, which is printed after each run.
21
+ # --seed 1234
22
+ #config.order = "random"
23
+ end
@@ -0,0 +1,30 @@
1
+ # This class is a stand in for an ActiveRecord or Mongoid::Document style class
2
+ TestJob = Struct.new :id,
3
+ :queue,
4
+ :status,
5
+ :enqueued_at,
6
+ :expire_execution_at,
7
+ :scheduled_at,
8
+ :completed_at,
9
+ :result,
10
+ :target,
11
+ :method,
12
+ :parameters,
13
+ :retry_count,
14
+ :retry_delay,
15
+ :timeout do
16
+ include JobDispatch::Job
17
+
18
+ def save!
19
+ true
20
+ end
21
+
22
+ def save
23
+ true
24
+ end
25
+
26
+ def reload
27
+ self
28
+ end
29
+
30
+ end
metadata ADDED
@@ -0,0 +1,255 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: job_dispatch
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Matt Connolly
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-04-20 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rbczmq
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.7'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: nullobject
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: json
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: text-table
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 1.2.3
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 1.2.3
69
+ - !ruby/object:Gem::Dependency
70
+ name: activesupport
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: 3.0.0
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: 3.0.0
83
+ - !ruby/object:Gem::Dependency
84
+ name: bundler
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '1.3'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '1.3'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rspec
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '2.14'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '2.14'
111
+ - !ruby/object:Gem::Dependency
112
+ name: simplecov
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '0.8'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '0.8'
125
+ - !ruby/object:Gem::Dependency
126
+ name: timecop
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '0.7'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '0.7'
139
+ - !ruby/object:Gem::Dependency
140
+ name: factory_girl
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: 4.3.0
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: 4.3.0
153
+ - !ruby/object:Gem::Dependency
154
+ name: rake
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ description: Job Dispatch to workers via ZeroMQ
168
+ email:
169
+ - matt@mobiledataanywhere.com
170
+ executables:
171
+ - job-dispatcher
172
+ - job-status
173
+ - job-worker
174
+ extensions: []
175
+ extra_rdoc_files: []
176
+ files:
177
+ - ".gitignore"
178
+ - ".rspec"
179
+ - ".travis.yml"
180
+ - Gemfile
181
+ - Guardfile
182
+ - LICENSE.txt
183
+ - README.md
184
+ - Rakefile
185
+ - bin/job-dispatcher
186
+ - bin/job-status
187
+ - bin/job-worker
188
+ - examples/mongoid-job.rb
189
+ - job_dispatch.gemspec
190
+ - lib/job_dispatch.rb
191
+ - lib/job_dispatch/broker.rb
192
+ - lib/job_dispatch/broker/command.rb
193
+ - lib/job_dispatch/broker/internal_job.rb
194
+ - lib/job_dispatch/broker/socket.rb
195
+ - lib/job_dispatch/client.rb
196
+ - lib/job_dispatch/client/proxy.rb
197
+ - lib/job_dispatch/client/proxy_error.rb
198
+ - lib/job_dispatch/client/synchronous_proxy.rb
199
+ - lib/job_dispatch/configuration.rb
200
+ - lib/job_dispatch/identity.rb
201
+ - lib/job_dispatch/job.rb
202
+ - lib/job_dispatch/signaller.rb
203
+ - lib/job_dispatch/sockets/enqueue.rb
204
+ - lib/job_dispatch/status.rb
205
+ - lib/job_dispatch/version.rb
206
+ - lib/job_dispatch/worker.rb
207
+ - lib/job_dispatch/worker/item.rb
208
+ - lib/job_dispatch/worker/socket.rb
209
+ - spec/factories/jobs.rb
210
+ - spec/job_dispatch/broker/socket_spec.rb
211
+ - spec/job_dispatch/broker_spec.rb
212
+ - spec/job_dispatch/identity_spec.rb
213
+ - spec/job_dispatch/job_spec.rb
214
+ - spec/job_dispatch/worker/socket_spec.rb
215
+ - spec/job_dispatch/worker_spec.rb
216
+ - spec/job_dispatch_spec.rb
217
+ - spec/spec_helper.rb
218
+ - spec/support/test_job.rb
219
+ homepage: ''
220
+ licenses:
221
+ - MIT
222
+ metadata: {}
223
+ post_install_message:
224
+ rdoc_options: []
225
+ require_paths:
226
+ - lib
227
+ required_ruby_version: !ruby/object:Gem::Requirement
228
+ requirements:
229
+ - - ">="
230
+ - !ruby/object:Gem::Version
231
+ version: '0'
232
+ required_rubygems_version: !ruby/object:Gem::Requirement
233
+ requirements:
234
+ - - ">="
235
+ - !ruby/object:Gem::Version
236
+ version: '0'
237
+ requirements: []
238
+ rubyforge_project:
239
+ rubygems_version: 2.2.2
240
+ signing_key:
241
+ specification_version: 4
242
+ summary: Job Dispatch is a gem for dispatching jobs to workers in an asynchronous
243
+ manner. Job Dispatch does not require any specific database. Jobs are dispatched
244
+ using ZeroMQ messages and workers can be implemented in any language.
245
+ test_files:
246
+ - spec/factories/jobs.rb
247
+ - spec/job_dispatch/broker/socket_spec.rb
248
+ - spec/job_dispatch/broker_spec.rb
249
+ - spec/job_dispatch/identity_spec.rb
250
+ - spec/job_dispatch/job_spec.rb
251
+ - spec/job_dispatch/worker/socket_spec.rb
252
+ - spec/job_dispatch/worker_spec.rb
253
+ - spec/job_dispatch_spec.rb
254
+ - spec/spec_helper.rb
255
+ - spec/support/test_job.rb