eq 0.0.1 → 0.1.0

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