eq 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. data/.gitignore +1 -0
  2. data/README.md +51 -11
  3. data/TODO.md +10 -0
  4. data/benchmarks/all.rb +13 -0
  5. data/benchmarks/parallel.rb +23 -0
  6. data/benchmarks/queue_backend_benchmark.rb +27 -0
  7. data/benchmarks/queueing.rb +13 -23
  8. data/benchmarks/working.rb +14 -25
  9. data/eq.gemspec +12 -2
  10. data/examples/queueing.rb +2 -2
  11. data/examples/scheduling.rb +19 -0
  12. data/examples/simple_usage.rb +20 -8
  13. data/examples/working.rb +2 -2
  14. data/lib/eq-queueing.rb +4 -13
  15. data/lib/eq-queueing/backends.rb +30 -1
  16. data/lib/eq-queueing/backends/leveldb.rb +232 -0
  17. data/lib/eq-queueing/backends/sequel.rb +34 -17
  18. data/lib/eq-queueing/queue.rb +26 -20
  19. data/lib/eq-scheduling.rb +33 -0
  20. data/lib/eq-scheduling/scheduler.rb +19 -0
  21. data/lib/eq-web.rb +5 -0
  22. data/lib/eq-web/server.rb +39 -0
  23. data/lib/eq-web/views/index.erb +45 -0
  24. data/lib/eq-working.rb +15 -7
  25. data/lib/eq-working/worker.rb +30 -3
  26. data/lib/eq.rb +39 -31
  27. data/lib/eq/boot/all.rb +1 -0
  28. data/lib/eq/boot/scheduling.rb +1 -0
  29. data/lib/eq/error.rb +4 -0
  30. data/lib/eq/job.rb +22 -16
  31. data/lib/eq/version.rb +1 -1
  32. data/log/.gitkeep +1 -0
  33. data/spec/lib/eq-queueing/backends/leveldb_spec.rb +32 -0
  34. data/spec/lib/eq-queueing/backends/sequel_spec.rb +5 -4
  35. data/spec/lib/eq-queueing/queue_spec.rb +27 -58
  36. data/spec/lib/eq-queueing_spec.rb +16 -0
  37. data/spec/lib/eq-scheduling_spec.rb +7 -0
  38. data/spec/lib/eq-working/worker_spec.rb +13 -0
  39. data/spec/lib/eq/job_spec.rb +16 -11
  40. data/spec/lib/eq_spec.rb +1 -1
  41. data/spec/mocks/a_job.rb +4 -0
  42. data/spec/mocks/a_unique_job.rb +6 -0
  43. data/spec/spec_helper.rb +12 -0
  44. data/spec/support/shared_examples_for_queue.rb +60 -31
  45. metadata +80 -8
  46. data/lib/eq-working/manager.rb +0 -31
  47. data/lib/eq-working/system.rb +0 -10
@@ -0,0 +1,16 @@
1
+ require 'spec_helper'
2
+
3
+ describe EQ do
4
+ context 'transient queueing' do
5
+ it "won't survives at least a dying queue actor" do
6
+ # setup a in-memory queue backend
7
+ EQ.config {|c| c.queue = 'sequel'; c.sequel = 'sqlite:/'}
8
+ EQ.boot :queue
9
+ EQ.queue.push AJob
10
+ EQ.queue.count.should == 1
11
+ EQ.shutdown
12
+ EQ.boot :queue
13
+ EQ.queue.count.should == 0
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,7 @@
1
+ require 'spec_helper'
2
+
3
+ describe EQ::Scheduling do
4
+ it 'list of events is empty per default' do
5
+ EQ::Scheduling.events.should == []
6
+ end
7
+ end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+ describe EQ::Working::Worker do
4
+ subject { EQ::Working::Worker.new false }
5
+
6
+ it 'loops for new jobs' do
7
+ pending
8
+ end
9
+
10
+ it 'performs jobs' do
11
+ pending
12
+ end
13
+ end
@@ -1,26 +1,31 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe EQ::Job do |variable|
4
- it 'dumps const and payload' do
5
- payload = EQ::Job.dump([EQ, 'bar', 'baz'])
6
- Marshal.load(payload).should == [EQ, 'bar', 'baz']
3
+ describe EQ::Job do
4
+
5
+ it 'creates a job with payload' do
6
+ job = EQ::Job.new nil, EQ::Job, ['bar', 'foo']
7
+ job.id.should == nil
8
+ job.queue.should == "EQ::Job"
9
+ job.job_class.should == EQ::Job
10
+ job.payload.should == ['bar', 'foo']
7
11
  end
8
12
 
9
- it 'loads const and payload' do
10
- serialized_payload = Marshal.dump [EQ, 'foo', 'bar']
11
- job = EQ::Job.load(1, serialized_payload)
12
- job.unpack.should == [EQ, 'foo', 'bar']
13
+ it 'creates a job without payload' do
14
+ job = EQ::Job.new nil, EQ::Job
15
+ job.id.should == nil
16
+ job.queue.should == "EQ::Job"
17
+ job.job_class.should == EQ::Job
18
+ job.payload.should == nil
13
19
  end
14
20
 
15
- it 'performs using const.perform(*payload)' do
21
+ it 'performs using queue.perform(*payload)' do
16
22
  class MyJob
17
23
  def self.perform(*args)
18
24
  {result: args}
19
25
  end
20
26
  end
21
27
  my_job_args = [1,2,3]
22
- serialized_payload = EQ::Job.dump(MyJob, *my_job_args)
23
- job = EQ::Job.load(1, serialized_payload)
28
+ job = EQ::Job.new(nil, MyJob, my_job_args)
24
29
  job.perform.should == {result: my_job_args}
25
30
  end
26
31
  end
@@ -1,5 +1,5 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe EQ do
4
-
4
+
5
5
  end
@@ -0,0 +1,4 @@
1
+ class AJob
2
+ def self.perform *args
3
+ end
4
+ end
@@ -0,0 +1,6 @@
1
+ class AUniqueJob
2
+ @unique = true
3
+
4
+ def self.perform *args
5
+ end
6
+ end
@@ -4,8 +4,14 @@
4
4
  # loaded once.
5
5
  #
6
6
  # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
7
+
8
+ require 'fileutils'
9
+
7
10
  require File.join(File.dirname(__FILE__), '..', 'lib', 'eq', 'boot', 'all')
8
11
  Dir[File.join(File.dirname(__FILE__), '/support/**/*.rb')].each {|f| require f; puts f}
12
+ Dir[File.join(File.dirname(__FILE__), '/mocks/**/*.rb')].each {|f| require f; puts f}
13
+
14
+ Celluloid.logger = Logger.new(File.join(File.dirname(__FILE__), '..', 'log', 'rspec.log'))
9
15
 
10
16
  RSpec.configure do |config|
11
17
  config.treat_symbols_as_metadata_keys_with_true_values = true
@@ -17,6 +23,12 @@ RSpec.configure do |config|
17
23
  # the seed, which is printed after each run.
18
24
  # --seed 1234
19
25
  config.order = 'random'
26
+
27
+ config.before :suite do
28
+ # cleanup rspec files
29
+ FileUtils.rm_rf 'tmp/rspec'
30
+ FileUtils.mkdir_p 'tmp/rspec'
31
+ end
20
32
  end
21
33
 
22
34
  require "timecop"
@@ -1,75 +1,104 @@
1
1
  shared_examples_for 'queue backend' do
2
- it 'pushes and pops' do
3
- subject.push "foo"
4
- job_id, payload = *subject.reserve
5
- job_id.should == 1
6
- payload.should == "foo"
2
+ let(:eq_job) { EQ::Job.new(nil, AJob, 'foo') }
3
+
4
+ it 'has no jobs at the beginning' do
5
+ subject.count(:jobs).should == 0
6
+ subject.count(:waiting).should == 0
7
+ subject.count(:working).should == 0
7
8
  end
8
- end
9
9
 
10
- shared_examples_for 'abstract queue' do
11
10
  it 'pushes jobs' do
12
- subject.waiting_count.should == 0
13
- subject.working_count.should == 0
14
- subject.push("foo").should == 1 # job id
15
- subject.waiting_count.should == 1
16
- subject.working_count.should == 0
11
+ subject.push(eq_job).should_not be_nil # job_id
12
+ subject.count(:jobs).should == 1
13
+ subject.count(:waiting).should == 1
14
+ subject.count(:working).should == 0
17
15
  end
18
16
 
19
17
  it 'reserves jobs' do
20
- id = subject.push "foo"
21
- subject.reserve
22
- subject.waiting_count.should == 0
23
- subject.working_count.should == 1
24
- subject.pop id
25
- subject.waiting_count.should == 0
26
- subject.working_count.should == 0
18
+ id = subject.push eq_job
19
+ subject.count(:jobs).should == 1
20
+ subject.count(:waiting).should == 1
21
+ subject.count(:working).should == 0
22
+ job = subject.reserve
23
+ id.should == job.id
24
+ subject.count(:jobs).should == 1
25
+ subject.count(:waiting).should == 0
26
+ subject.count(:working).should == 1
27
27
  end
28
28
 
29
29
  it 'pops jobs' do
30
30
  subject.pop(1).should be_false # no job
31
- subject.push "foo"
32
- subject.pop(1).should be_true # one job
31
+ job_id = subject.push eq_job
32
+ subject.count(:jobs).should == 1
33
+ subject.count(:waiting).should == 1
34
+ subject.count(:working).should == 0
35
+ subject.pop(job_id).should be_true # one job
36
+ subject.count(:jobs).should == 0
37
+ subject.count(:waiting).should == 0
38
+ subject.count(:working).should == 0
33
39
  subject.pop(1).should be_false # again no job"
34
40
  end
35
41
 
42
+ it 'clears jobs' do
43
+ 10.times { subject.push(eq_job) }
44
+ subject.count.should == 10
45
+ subject.clear
46
+ subject.count.should == 0
47
+ end
48
+
36
49
  it 'puts working job back on waiting when they timeout via #requeue_timed_out_jobs' do
37
50
  # freeze time on start of 1986
38
51
  Timecop.freeze(Time.new(1986)) do
39
52
 
40
53
  # create a job
41
- id = subject.push "foo"
54
+ id = subject.push eq_job
42
55
 
43
56
  # start working
44
57
  data = subject.reserve
45
58
 
46
59
  # no on working at the beginning
47
- subject.waiting_count.should == 0
48
- subject.working_count.should == 1
60
+ subject.count(:waiting).should == 0
61
+ subject.count(:working).should == 1
49
62
 
50
63
  # no one will be re-enqueued
51
64
  subject.requeue_timed_out_jobs.should == 0
52
65
 
53
66
  # no on working after senseless re-enqueueing
54
- subject.waiting_count.should == 0
55
- subject.working_count.should == 1
56
-
67
+ subject.count(:waiting).should == 0
68
+ subject.count(:working).should == 1
57
69
  end
58
70
 
59
71
  # freeze the time to 10s in the future
60
72
  Timecop.freeze(Time.new(1986, 01, 01, 00, 00, EQ.config.job_timeout)) do
61
73
 
62
74
  # nothing happened yet...
63
- subject.waiting_count.should == 0
64
- subject.working_count.should == 1
75
+ subject.count(:waiting).should == 0
76
+ subject.count(:working).should == 1
65
77
 
66
78
  # this time one will be re-enqueued
67
79
  subject.requeue_timed_out_jobs.should == 1
68
80
 
69
81
  # now the old job is available again
70
- subject.waiting_count.should == 1
71
- subject.working_count.should == 0
82
+ subject.count(:waiting).should == 1
83
+ subject.count(:working).should == 0
84
+ end
85
+ end
86
+
87
+ context 'unique jobs' do
88
+ it 'does not enqueue multiple times when args are the same' do
89
+ subject.count.should == 0
90
+ id = subject.push EQ::Job.new(nil, AUniqueJob)
91
+ subject.count.should == 1
92
+ id = subject.push EQ::Job.new(nil, AUniqueJob)
93
+ subject.count.should == 1
94
+ end
72
95
 
96
+ it 'does enqueue multiple times when args differ' do
97
+ subject.count.should == 0
98
+ id = subject.push EQ::Job.new(nil, AUniqueJob, 'foo')
99
+ subject.count.should == 1
100
+ id = subject.push EQ::Job.new(nil, AUniqueJob, 'bar')
101
+ subject.count.should == 2
73
102
  end
74
103
  end
75
104
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: eq
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,10 +9,10 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-08-23 00:00:00.000000000 Z
12
+ date: 2012-09-18 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
- name: sqlite3
15
+ name: celluloid
16
16
  requirement: !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
@@ -27,6 +27,38 @@ dependencies:
27
27
  - - ! '>='
28
28
  - !ruby/object:Gem::Version
29
29
  version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: sinatra
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: clockwork
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'
30
62
  - !ruby/object:Gem::Dependency
31
63
  name: sequel
32
64
  requirement: !ruby/object:Gem::Requirement
@@ -35,7 +67,7 @@ dependencies:
35
67
  - - ! '>='
36
68
  - !ruby/object:Gem::Version
37
69
  version: '0'
38
- type: :runtime
70
+ type: :development
39
71
  prerelease: false
40
72
  version_requirements: !ruby/object:Gem::Requirement
41
73
  none: false
@@ -44,14 +76,30 @@ dependencies:
44
76
  - !ruby/object:Gem::Version
45
77
  version: '0'
46
78
  - !ruby/object:Gem::Dependency
47
- name: celluloid
79
+ name: sqlite3
48
80
  requirement: !ruby/object:Gem::Requirement
49
81
  none: false
50
82
  requirements:
51
83
  - - ! '>='
52
84
  - !ruby/object:Gem::Version
53
85
  version: '0'
54
- type: :runtime
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: leveldb-ruby
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ type: :development
55
103
  prerelease: false
56
104
  version_requirements: !ruby/object:Gem::Requirement
57
105
  none: false
@@ -155,31 +203,49 @@ files:
155
203
  - LICENSE
156
204
  - README.md
157
205
  - Rakefile
206
+ - TODO.md
207
+ - benchmarks/all.rb
208
+ - benchmarks/parallel.rb
209
+ - benchmarks/queue_backend_benchmark.rb
158
210
  - benchmarks/queueing.rb
159
211
  - benchmarks/working.rb
160
212
  - eq.gemspec
161
213
  - examples/queueing.rb
214
+ - examples/scheduling.rb
162
215
  - examples/simple_usage.rb
163
216
  - examples/working.rb
164
217
  - lib/eq-queueing.rb
165
218
  - lib/eq-queueing/backends.rb
219
+ - lib/eq-queueing/backends/leveldb.rb
166
220
  - lib/eq-queueing/backends/sequel.rb
167
221
  - lib/eq-queueing/queue.rb
222
+ - lib/eq-scheduling.rb
223
+ - lib/eq-scheduling/scheduler.rb
224
+ - lib/eq-web.rb
225
+ - lib/eq-web/server.rb
226
+ - lib/eq-web/views/index.erb
168
227
  - lib/eq-working.rb
169
- - lib/eq-working/manager.rb
170
- - lib/eq-working/system.rb
171
228
  - lib/eq-working/worker.rb
172
229
  - lib/eq.rb
173
230
  - lib/eq/boot/all.rb
174
231
  - lib/eq/boot/queueing.rb
232
+ - lib/eq/boot/scheduling.rb
175
233
  - lib/eq/boot/working.rb
234
+ - lib/eq/error.rb
176
235
  - lib/eq/job.rb
177
236
  - lib/eq/logging.rb
178
237
  - lib/eq/version.rb
238
+ - log/.gitkeep
239
+ - spec/lib/eq-queueing/backends/leveldb_spec.rb
179
240
  - spec/lib/eq-queueing/backends/sequel_spec.rb
180
241
  - spec/lib/eq-queueing/queue_spec.rb
242
+ - spec/lib/eq-queueing_spec.rb
243
+ - spec/lib/eq-scheduling_spec.rb
244
+ - spec/lib/eq-working/worker_spec.rb
181
245
  - spec/lib/eq/job_spec.rb
182
246
  - spec/lib/eq_spec.rb
247
+ - spec/mocks/a_job.rb
248
+ - spec/mocks/a_unique_job.rb
183
249
  - spec/spec_helper.rb
184
250
  - spec/support/shared_examples_for_queue.rb
185
251
  homepage: https://github.com/dpree/eq
@@ -208,10 +274,16 @@ specification_version: 3
208
274
  summary: Based on Celluloid (multi-threading) and Sequel (SQLite3, MySQL, PostgreSQL,
209
275
  ...).
210
276
  test_files:
277
+ - spec/lib/eq-queueing/backends/leveldb_spec.rb
211
278
  - spec/lib/eq-queueing/backends/sequel_spec.rb
212
279
  - spec/lib/eq-queueing/queue_spec.rb
280
+ - spec/lib/eq-queueing_spec.rb
281
+ - spec/lib/eq-scheduling_spec.rb
282
+ - spec/lib/eq-working/worker_spec.rb
213
283
  - spec/lib/eq/job_spec.rb
214
284
  - spec/lib/eq_spec.rb
285
+ - spec/mocks/a_job.rb
286
+ - spec/mocks/a_unique_job.rb
215
287
  - spec/spec_helper.rb
216
288
  - spec/support/shared_examples_for_queue.rb
217
289
  has_rdoc:
@@ -1,31 +0,0 @@
1
- module EQ::Working
2
- class Manager
3
- include Celluloid
4
- include EQ::Logging
5
-
6
- def initialize
7
- run!
8
- end
9
-
10
- # polls the EQ.queue via EQ.queue.reserve
11
- def run
12
- debug "worker manager running"
13
- loop do
14
- if EQ.queue && job = EQ.queue.reserve
15
- debug "got #{job.inspect}"
16
- if worker = EQ::Working.worker_pool
17
- debug ' - found worker'
18
- worker.process! job
19
- else
20
- debug ' - no worker'
21
- end
22
- else
23
- # currently no job
24
- end
25
- sleep 0.01
26
- end
27
- rescue Celluloid::DeadActorError
28
- retry
29
- end
30
- end
31
- end