asynchronic 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 (44) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -0
  3. data/README.md +0 -70
  4. data/Rakefile +7 -0
  5. data/asynchronic.gemspec +5 -1
  6. data/lib/asynchronic/data_store/in_memory.rb +47 -0
  7. data/lib/asynchronic/data_store/key.rb +15 -0
  8. data/lib/asynchronic/data_store/lookup.rb +27 -0
  9. data/lib/asynchronic/data_store/redis.rb +52 -0
  10. data/lib/asynchronic/environment.rb +57 -0
  11. data/lib/asynchronic/error.rb +13 -0
  12. data/lib/asynchronic/hash.rb +31 -0
  13. data/lib/asynchronic/job.rb +46 -0
  14. data/lib/asynchronic/process.rb +117 -48
  15. data/lib/asynchronic/queue_engine/in_memory.rb +72 -0
  16. data/lib/asynchronic/queue_engine/ost.rb +73 -0
  17. data/lib/asynchronic/runtime.rb +40 -0
  18. data/lib/asynchronic/version.rb +1 -1
  19. data/lib/asynchronic/worker.rb +27 -18
  20. data/lib/asynchronic.rb +17 -32
  21. data/spec/coverage_helper.rb +0 -6
  22. data/spec/data_store/data_store_examples.rb +62 -0
  23. data/spec/data_store/in_memory_spec.rb +10 -0
  24. data/spec/data_store/key_spec.rb +36 -0
  25. data/spec/data_store/lookup_spec.rb +92 -0
  26. data/spec/data_store/redis_spec.rb +14 -0
  27. data/spec/expectations.rb +89 -0
  28. data/spec/facade_spec.rb +61 -0
  29. data/spec/jobs.rb +123 -33
  30. data/spec/minitest_helper.rb +12 -14
  31. data/spec/process/life_cycle_examples.rb +329 -0
  32. data/spec/process/life_cycle_in_memory_spec.rb +11 -0
  33. data/spec/process/life_cycle_redis_spec.rb +15 -0
  34. data/spec/queue_engine/in_memory_spec.rb +11 -0
  35. data/spec/queue_engine/ost_spec.rb +15 -0
  36. data/spec/queue_engine/queue_engine_examples.rb +47 -0
  37. data/spec/worker/in_memory_spec.rb +11 -0
  38. data/spec/worker/redis_spec.rb +16 -0
  39. data/spec/worker/worker_examples.rb +49 -0
  40. metadata +111 -18
  41. data/lib/asynchronic/persistent.rb +0 -61
  42. data/lib/asynchronic/pipeline.rb +0 -23
  43. data/spec/integration_spec.rb +0 -122
  44. data/spec/persistent_spec.rb +0 -88
@@ -0,0 +1,49 @@
1
+ module WorkerExamples
2
+
3
+ let(:env) { Asynchronic::Environment.new queue_engine, data_store }
4
+ let(:queue_name) { :test_worker }
5
+ let(:queue) { env.queue queue_name }
6
+
7
+ def enqueue_processes
8
+ processes = 5.times.map do
9
+ env.build_process(WorkerJob, queue: :test_worker).tap(&:enqueue)
10
+ end
11
+
12
+ queue.must_enqueued processes
13
+ processes.each { |p| p.must_be :queued? }
14
+
15
+ processes
16
+ end
17
+
18
+ it 'Instance usage' do
19
+ worker = Asynchronic::Worker.new :test_worker, env
20
+
21
+ processes = enqueue_processes
22
+
23
+ Thread.new do
24
+ loop { break if queue.empty? }
25
+ worker.stop
26
+ end
27
+
28
+ worker.start
29
+
30
+ processes.each { |p| p.must_be :completed? }
31
+ end
32
+
33
+ it 'Class usage' do
34
+ Asynchronic.configure do |config|
35
+ config.queue_engine = queue_engine
36
+ config.data_store = data_store
37
+ end
38
+
39
+ processes = enqueue_processes
40
+
41
+ Asynchronic::Worker.start :test_worker do |worker|
42
+ loop { break if worker.queue.empty? }
43
+ worker.stop
44
+ end
45
+
46
+ processes.each { |p| p.must_be :completed? }
47
+ end
48
+
49
+ end
metadata CHANGED
@@ -1,99 +1,155 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: asynchronic
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gabriel Naiman
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-11-29 00:00:00.000000000 Z
11
+ date: 2014-03-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: ost
14
+ name: redis
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '3.0'
20
+ type: :runtime
15
21
  prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '3.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: ost
16
29
  requirement: !ruby/object:Gem::Requirement
17
30
  requirements:
18
31
  - - "~>"
19
32
  - !ruby/object:Gem::Version
20
33
  version: '0.1'
34
+ type: :runtime
35
+ prerelease: false
21
36
  version_requirements: !ruby/object:Gem::Requirement
22
37
  requirements:
23
38
  - - "~>"
24
39
  - !ruby/object:Gem::Version
25
40
  version: '0.1'
41
+ - !ruby/object:Gem::Dependency
42
+ name: class_config
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0.0'
26
48
  type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '0.0'
27
55
  - !ruby/object:Gem::Dependency
28
56
  name: bundler
29
- prerelease: false
30
57
  requirement: !ruby/object:Gem::Requirement
31
58
  requirements:
32
59
  - - "~>"
33
60
  - !ruby/object:Gem::Version
34
61
  version: '1.3'
62
+ type: :development
63
+ prerelease: false
35
64
  version_requirements: !ruby/object:Gem::Requirement
36
65
  requirements:
37
66
  - - "~>"
38
67
  - !ruby/object:Gem::Version
39
68
  version: '1.3'
40
- type: :development
41
69
  - !ruby/object:Gem::Dependency
42
70
  name: rake
43
- prerelease: false
44
71
  requirement: !ruby/object:Gem::Requirement
45
72
  requirements:
46
73
  - - ">="
47
74
  - !ruby/object:Gem::Version
48
75
  version: '0'
76
+ type: :development
77
+ prerelease: false
49
78
  version_requirements: !ruby/object:Gem::Requirement
50
79
  requirements:
51
80
  - - ">="
52
81
  - !ruby/object:Gem::Version
53
82
  version: '0'
54
- type: :development
55
83
  - !ruby/object:Gem::Dependency
56
84
  name: minitest
57
- prerelease: false
58
85
  requirement: !ruby/object:Gem::Requirement
59
86
  requirements:
60
87
  - - "~>"
61
88
  - !ruby/object:Gem::Version
62
89
  version: '4.7'
90
+ type: :development
91
+ prerelease: false
63
92
  version_requirements: !ruby/object:Gem::Requirement
64
93
  requirements:
65
94
  - - "~>"
66
95
  - !ruby/object:Gem::Version
67
96
  version: '4.7'
97
+ - !ruby/object:Gem::Dependency
98
+ name: minitest-great_expectations
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '0.0'
68
104
  type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '0.0'
69
111
  - !ruby/object:Gem::Dependency
70
112
  name: turn
71
- prerelease: false
72
113
  requirement: !ruby/object:Gem::Requirement
73
114
  requirements:
74
115
  - - "~>"
75
116
  - !ruby/object:Gem::Version
76
117
  version: '0.9'
118
+ type: :development
119
+ prerelease: false
77
120
  version_requirements: !ruby/object:Gem::Requirement
78
121
  requirements:
79
122
  - - "~>"
80
123
  - !ruby/object:Gem::Version
81
124
  version: '0.9'
82
- type: :development
83
125
  - !ruby/object:Gem::Dependency
84
126
  name: simplecov
85
- prerelease: false
86
127
  requirement: !ruby/object:Gem::Requirement
87
128
  requirements:
88
129
  - - ">="
89
130
  - !ruby/object:Gem::Version
90
131
  version: '0'
132
+ type: :development
133
+ prerelease: false
91
134
  version_requirements: !ruby/object:Gem::Requirement
92
135
  requirements:
93
136
  - - ">="
94
137
  - !ruby/object:Gem::Version
95
138
  version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: pry
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
96
146
  type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
97
153
  description: DSL for asynchronic pipeline
98
154
  email:
99
155
  - gabynaiman@gmail.com
@@ -110,16 +166,39 @@ files:
110
166
  - Rakefile
111
167
  - asynchronic.gemspec
112
168
  - lib/asynchronic.rb
113
- - lib/asynchronic/persistent.rb
114
- - lib/asynchronic/pipeline.rb
169
+ - lib/asynchronic/data_store/in_memory.rb
170
+ - lib/asynchronic/data_store/key.rb
171
+ - lib/asynchronic/data_store/lookup.rb
172
+ - lib/asynchronic/data_store/redis.rb
173
+ - lib/asynchronic/environment.rb
174
+ - lib/asynchronic/error.rb
175
+ - lib/asynchronic/hash.rb
176
+ - lib/asynchronic/job.rb
115
177
  - lib/asynchronic/process.rb
178
+ - lib/asynchronic/queue_engine/in_memory.rb
179
+ - lib/asynchronic/queue_engine/ost.rb
180
+ - lib/asynchronic/runtime.rb
116
181
  - lib/asynchronic/version.rb
117
182
  - lib/asynchronic/worker.rb
118
183
  - spec/coverage_helper.rb
119
- - spec/integration_spec.rb
184
+ - spec/data_store/data_store_examples.rb
185
+ - spec/data_store/in_memory_spec.rb
186
+ - spec/data_store/key_spec.rb
187
+ - spec/data_store/lookup_spec.rb
188
+ - spec/data_store/redis_spec.rb
189
+ - spec/expectations.rb
190
+ - spec/facade_spec.rb
120
191
  - spec/jobs.rb
121
192
  - spec/minitest_helper.rb
122
- - spec/persistent_spec.rb
193
+ - spec/process/life_cycle_examples.rb
194
+ - spec/process/life_cycle_in_memory_spec.rb
195
+ - spec/process/life_cycle_redis_spec.rb
196
+ - spec/queue_engine/in_memory_spec.rb
197
+ - spec/queue_engine/ost_spec.rb
198
+ - spec/queue_engine/queue_engine_examples.rb
199
+ - spec/worker/in_memory_spec.rb
200
+ - spec/worker/redis_spec.rb
201
+ - spec/worker/worker_examples.rb
123
202
  homepage: https://github.com/gabynaiman/asynchronic
124
203
  licenses:
125
204
  - MIT
@@ -140,13 +219,27 @@ required_rubygems_version: !ruby/object:Gem::Requirement
140
219
  version: '0'
141
220
  requirements: []
142
221
  rubyforge_project:
143
- rubygems_version: 2.1.5
222
+ rubygems_version: 2.2.2
144
223
  signing_key:
145
224
  specification_version: 4
146
225
  summary: DSL for asynchronic pipeline using queues over Redis
147
226
  test_files:
148
227
  - spec/coverage_helper.rb
149
- - spec/integration_spec.rb
228
+ - spec/data_store/data_store_examples.rb
229
+ - spec/data_store/in_memory_spec.rb
230
+ - spec/data_store/key_spec.rb
231
+ - spec/data_store/lookup_spec.rb
232
+ - spec/data_store/redis_spec.rb
233
+ - spec/expectations.rb
234
+ - spec/facade_spec.rb
150
235
  - spec/jobs.rb
151
236
  - spec/minitest_helper.rb
152
- - spec/persistent_spec.rb
237
+ - spec/process/life_cycle_examples.rb
238
+ - spec/process/life_cycle_in_memory_spec.rb
239
+ - spec/process/life_cycle_redis_spec.rb
240
+ - spec/queue_engine/in_memory_spec.rb
241
+ - spec/queue_engine/ost_spec.rb
242
+ - spec/queue_engine/queue_engine_examples.rb
243
+ - spec/worker/in_memory_spec.rb
244
+ - spec/worker/redis_spec.rb
245
+ - spec/worker/worker_examples.rb
@@ -1,61 +0,0 @@
1
- module Asynchronic
2
- module Persistent
3
-
4
- def self.included(base)
5
- base.send :include, InstanceMethods
6
- base.extend ClassMethods
7
- end
8
-
9
- module InstanceMethods
10
-
11
- def id
12
- @id
13
- end
14
-
15
- def save
16
- @id ||= SecureRandom.uuid
17
- nest.set Marshal.dump(self)
18
- end
19
-
20
- def delete
21
- return unless id
22
- nest.del
23
- end
24
-
25
- def archive
26
- return unless id
27
- FileUtils.mkpath(Asynchronic.archiving_path) unless Dir.exists?(Asynchronic.archiving_path)
28
- File.write Asynchronic.archiving_file(id), Base64.encode64(Marshal.dump(self))
29
- delete
30
- end
31
-
32
- def nest
33
- self.class.nest[id]
34
- end
35
-
36
- end
37
-
38
- module ClassMethods
39
-
40
- def create(*args, &block)
41
- new(*args, &block).tap(&:save)
42
- end
43
-
44
- def find(id)
45
- if nest[id].get
46
- Marshal.load nest[id].get
47
- elsif File.exists?(Asynchronic.archiving_file(id))
48
- Marshal.load(Base64.decode64(File.read(Asynchronic.archiving_file(id))))
49
- else
50
- nil
51
- end
52
- end
53
-
54
- def nest
55
- @nest ||= Nest.new self.name, Asynchronic.redis
56
- end
57
-
58
- end
59
-
60
- end
61
- end
@@ -1,23 +0,0 @@
1
- module Asynchronic
2
- module Pipeline
3
-
4
- Step = Struct.new :name, :options, :block
5
-
6
- def queue(name=nil)
7
- name ? @queue = name : @queue
8
- end
9
-
10
- def step(name, options={}, &block)
11
- steps << Step.new(name, options, block)
12
- end
13
-
14
- def steps
15
- @steps ||= []
16
- end
17
-
18
- def run(context={})
19
- Process.enqueue self, context
20
- end
21
-
22
- end
23
- end
@@ -1,122 +0,0 @@
1
- require 'minitest_helper'
2
- require 'jobs'
3
-
4
- describe 'Integration' do
5
-
6
- before do
7
- Registry.clear
8
- end
9
-
10
- def start_and_stop_worker(queue=nil)
11
- worker = Asynchronic::Worker.new queue
12
- Thread.new do
13
- sleep 0.1
14
- while Nest.new('ost')[worker.queue].exists; end
15
- worker.stop
16
- end
17
- worker.start
18
- end
19
-
20
- def exist_queue?(queue)
21
- Nest.new('ost')[queue].exists
22
- end
23
-
24
- it 'Job defaults' do
25
- SingleStepJob.queue.must_be_nil
26
- SingleStepJob.steps.count.must_equal 1
27
- SingleStepJob.steps[0].name.must_equal :step_name
28
- SingleStepJob.steps[0].options.must_equal Hash.new
29
- SingleStepJob.steps[0].block.class.must_equal Proc
30
- SingleStepJob.must_respond_to :run
31
- end
32
-
33
- it 'Process defaults' do
34
- pid = SingleStepJob.run
35
-
36
- pid.wont_be_nil
37
-
38
- process = Asynchronic::Process.find pid
39
-
40
- process.pipeline.must_equal SingleStepJob
41
- process.context.must_equal Hash.new
42
- process.children.count.must_equal 1
43
- process.children[0].status.must_equal :pending
44
- process.children[0].output.must_be_nil
45
- end
46
-
47
- describe 'Execution' do
48
-
49
- it 'One step job' do
50
- SingleStepJob.queue.must_be_nil
51
- refute exist_queue? Asynchronic.default_queue
52
-
53
- pid = SingleStepJob.run
54
-
55
- assert exist_queue? Asynchronic.default_queue
56
- Registry.must_be_empty
57
-
58
- start_and_stop_worker
59
-
60
- process = Asynchronic::Process.find pid
61
- process.children[0].status.must_equal :finalized
62
- process.children[0].output.must_equal :single_step_job
63
-
64
- Registry.to_a.must_equal [:single_step_job]
65
- end
66
-
67
- it 'Two steps with specific queue and context arguments' do
68
- TwoStepsWithSpecificQueueJob.queue.wont_be_nil
69
- refute exist_queue? TwoStepsWithSpecificQueueJob.queue
70
-
71
- pid = TwoStepsWithSpecificQueueJob.run value1: 10
72
-
73
- assert exist_queue? TwoStepsWithSpecificQueueJob.queue
74
- Registry.must_be_empty
75
-
76
- start_and_stop_worker TwoStepsWithSpecificQueueJob.queue
77
-
78
- process = Asynchronic::Process.find pid
79
- process.context.must_equal value1: 10, value2: 5
80
- process.children[0].status.must_equal :finalized
81
- process.children[0].output.must_equal 11
82
- process.children[1].status.must_equal :finalized
83
- process.children[1].output.must_equal 55
84
-
85
- Registry.to_a.must_equal [11, 55]
86
- end
87
-
88
- it 'Steps with different queues (fixed and contextual)' do
89
- MultipleQueuesJob.queue.must_be_nil
90
- refute exist_queue? :queue1
91
- refute exist_queue? :queue2
92
-
93
- pid = MultipleQueuesJob.run dynamic_queue: :queue2
94
-
95
- assert exist_queue? :queue1
96
- refute exist_queue? :queue2
97
- Registry.must_be_empty
98
-
99
- start_and_stop_worker :queue1
100
-
101
- process = Asynchronic::Process.find pid
102
- process.children[0].status.must_equal :finalized
103
- process.children[1].status.must_equal :pending
104
-
105
- refute exist_queue? :queue1
106
- assert exist_queue? :queue2
107
- Registry.to_a.must_equal [:first_queue]
108
-
109
- start_and_stop_worker :queue2
110
-
111
- process = Asynchronic::Process.find pid
112
- process.children[0].status.must_equal :finalized
113
- process.children[1].status.must_equal :finalized
114
-
115
- refute exist_queue? :queue1
116
- refute exist_queue? :queue2
117
- Registry.to_a.must_equal [:first_queue, :second_queue]
118
- end
119
-
120
- end
121
-
122
- end
@@ -1,88 +0,0 @@
1
- require 'minitest_helper'
2
-
3
- describe Asynchronic::Persistent do
4
-
5
- Dummy = Struct.new :string, :hash, :array do
6
- include Asynchronic::Persistent
7
- end
8
-
9
- def dummy_attributes
10
- ['text', {key1: 'value1', key2: 'value2'}, [1,2,3]]
11
- end
12
-
13
- def assert_dummy(obj)
14
- obj.string.must_equal 'text'
15
- obj.hash.must_equal key1: 'value1', key2: 'value2'
16
- obj.array.must_equal [1,2,3]
17
- end
18
-
19
- describe 'Instance methods' do
20
-
21
- let(:dummy) { Dummy.new *dummy_attributes }
22
-
23
- it 'Nest instance identifier' do
24
- dummy.define_singleton_method(:id) { '123456' }
25
- dummy.nest.must_equal 'Dummy:123456'
26
- end
27
-
28
- it 'Save' do
29
- dummy.id.must_equal nil
30
- dummy.save
31
- dummy.id.wont_equal nil
32
-
33
- redis.keys.must_include dummy.nest
34
-
35
- assert_dummy Marshal.load(redis.get(dummy.nest))
36
- end
37
-
38
- it 'Delete' do
39
- dummy.save
40
- redis.keys.must_include dummy.nest
41
-
42
- dummy.delete
43
- redis.keys.wont_include dummy.nest
44
- end
45
-
46
- it 'Archive' do
47
- dummy.save
48
- redis.keys.must_include dummy.nest
49
- refute File.exists?(Asynchronic.archiving_file(dummy.id))
50
-
51
- dummy.archive
52
- redis.keys.wont_include dummy.nest
53
- assert File.exists?(Asynchronic.archiving_file(dummy.id))
54
-
55
- assert_dummy Marshal.load(Base64.decode64(File.read(Asynchronic.archiving_file(dummy.id))))
56
- end
57
-
58
- end
59
-
60
- describe 'Class methods' do
61
-
62
- it 'Nest class identifier' do
63
- Dummy.nest.must_equal 'Dummy'
64
- end
65
-
66
- it 'Create' do
67
- dummy = Dummy.create *dummy_attributes
68
-
69
- redis.keys.must_include dummy.nest
70
- assert_dummy Marshal.load(redis.get(dummy.nest))
71
- end
72
-
73
- it 'Find' do
74
- dummy = Dummy.create *dummy_attributes
75
-
76
- assert_dummy Dummy.find(dummy.id)
77
- end
78
-
79
- it 'Find archived' do
80
- dummy = Dummy.create *dummy_attributes
81
- dummy.archive
82
-
83
- assert_dummy Dummy.find(dummy.id)
84
- end
85
-
86
- end
87
-
88
- end