resque_jobs_tree 0.4.3 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -52,7 +52,7 @@ Organise each sequences of jobs into a single file
52
52
  This code is defining the tree, then when it launches the sequence of jobs, it:
53
53
  * stocks in Redis all the Resque jobs which needs to be done including the needed parameters to run them.
54
54
  * stocks in Redis the childhood relationsips between them.
55
- * enqueues in Resque the jobs which are the leaves of the tree
55
+ * enqueues in Resque the jobs which are the nodes of the tree
56
56
 
57
57
  Limitations:
58
58
 
@@ -64,7 +64,7 @@ you can't enqueue 2 times `[:mail, User.first]`
64
64
 
65
65
  Node options:
66
66
 
67
- * `{ async: true }` if you need your process to wait for an outsider to continue.
67
+ * `{ triggerable: true }` if you need your process to wait for an outsider to start.
68
68
  * `{ continue_on_fail: true}` if your process can continue even after a fail during a job.
69
69
 
70
70
  ## Contributing
@@ -14,7 +14,11 @@ class ResqueJobsTree::Definitions::Node < ResqueJobsTree::Definitions
14
14
  ResqueJobsTree::Definitions::Node.new(name, tree, self).tap do |node|
15
15
  node.options = options
16
16
  @node_childs << node
17
- node.instance_eval(&block) if block_given?
17
+ if block_given?
18
+ node.instance_eval &block
19
+ elsif options.has_key? :triggerable
20
+ node.perform {}
21
+ end
18
22
  end
19
23
  end
20
24
 
@@ -49,18 +53,38 @@ class ResqueJobsTree::Definitions::Node < ResqueJobsTree::Definitions
49
53
  end
50
54
 
51
55
  def validate!
56
+ # Should have a child's naming [:job1, ...] and node childs Proc implementation associated
57
+ # node :job1 do
58
+ # perform {}
59
+ # end
60
+ # ...
52
61
  if (childs.kind_of?(Proc) && node_childs.empty?) || (childs.nil? && !node_childs.empty?)
53
62
  raise ResqueJobsTree::NodeDefinitionInvalid,
54
63
  "node `#{name}` from tree `#{tree.name}` should defines childs and child nodes"
55
64
  end
56
- unless perform.kind_of? Proc
65
+
66
+ # Should have an implementation
67
+ # node :job1 do
68
+ # perform {}
69
+ # end
70
+ if !perform.kind_of? Proc and !options.has_key? :triggerable
57
71
  raise ResqueJobsTree::NodeDefinitionInvalid,
58
72
  "node `#{name}` from tree `#{tree.name}` has no perform block"
59
73
  end
74
+
75
+ # Naming Should be uniq
60
76
  if (tree.nodes - [self]).map(&:name).include? name
61
77
  raise ResqueJobsTree::NodeDefinitionInvalid,
62
78
  "node name `#{name}` is already taken in tree `#{tree.name}`"
63
79
  end
80
+
81
+ # Only one job can be trigger tree
82
+ if node_childs.select { |entry| entry.options.has_key?(:triggerable) }.size > 1
83
+ raise ResqueJobsTree::NodeDefinitionInvalid,
84
+ "Only one job must be declared to be triggerable into an definition, tree `#{tree.name}`"
85
+ end
86
+
87
+ # Recursive call for validate all of tree
64
88
  node_childs.each &:validate!
65
89
  end
66
90
 
@@ -12,7 +12,7 @@ class ResqueJobsTree::Definitions::Tree < ResqueJobsTree::Definitions
12
12
 
13
13
  def root name=nil, &block
14
14
  @root ||= Node.new(name, self).tap do |root|
15
- root.instance_eval &block
15
+ root.instance_eval &block if block_given?
16
16
  end
17
17
  end
18
18
 
@@ -1,5 +1,4 @@
1
1
  module ResqueJobsTree::Factory
2
-
3
2
  extend self
4
3
 
5
4
  def create name, &block
@@ -70,14 +70,14 @@ class ResqueJobsTree::Node
70
70
  @childs = definition.leaf? ? [] : definition.childs.call(*resources)
71
71
  end
72
72
 
73
- def launch
73
+ def register
74
74
  store unless root?
75
75
  if leaf?
76
- tree.register_a_leaf self
76
+ tree.register_node self
77
77
  else
78
78
  childs.each do |node_name, *resources|
79
79
  node = definition.find(node_name).spawn resources, self
80
- node.launch
80
+ node.register
81
81
  end
82
82
  end
83
83
  end
@@ -96,7 +96,7 @@ class ResqueJobsTree::Node
96
96
  puts "[ResqueJobsTree::Tree] after_perform callback of node #{definition.tree.name}##{name} has failed."\
97
97
  " Continuing for cleanup."
98
98
  else
99
- raise
99
+ raise
100
100
  end
101
101
  end
102
102
 
@@ -2,12 +2,12 @@ class ResqueJobsTree::Tree
2
2
 
3
3
  include ResqueJobsTree::Storage::Tree
4
4
 
5
- attr_reader :definition, :resources, :leaves
5
+ attr_reader :definition, :resources, :nodes
6
6
 
7
7
  def initialize definition, resources
8
8
  @definition = definition
9
9
  @resources = resources
10
- @leaves = []
10
+ @nodes = []
11
11
  end
12
12
 
13
13
  def name
@@ -18,8 +18,11 @@ class ResqueJobsTree::Tree
18
18
  if uniq?
19
19
  before_perform
20
20
  store
21
- root.launch
22
- enqueue_leaves_jobs
21
+ root.register
22
+ enqueue_jobs
23
+ else
24
+ raise ResqueJobsTree::JobNotUniq,
25
+ "Tree Definition must be uniq"
23
26
  end
24
27
  end
25
28
 
@@ -37,8 +40,8 @@ class ResqueJobsTree::Tree
37
40
  @root ||= ResqueJobsTree::Node.new(definition.root, resources, nil, self)
38
41
  end
39
42
 
40
- def register_a_leaf node
41
- @leaves << node
43
+ def register_node node
44
+ @nodes << node
42
45
  end
43
46
 
44
47
  def inspect
@@ -52,9 +55,9 @@ class ResqueJobsTree::Tree
52
55
 
53
56
  private
54
57
 
55
- def enqueue_leaves_jobs
56
- @leaves.each do |leaf|
57
- leaf.enqueue unless leaf.definition.options[:async]
58
+ def enqueue_jobs
59
+ @nodes.each do |leaf|
60
+ leaf.enqueue unless leaf.definition.options[:triggerable]
58
61
  end
59
62
  end
60
63
 
@@ -1,3 +1,3 @@
1
1
  module ResqueJobsTree
2
- VERSION = "0.4.3"
2
+ VERSION = "0.5.0"
3
3
  end
@@ -4,23 +4,24 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
  require 'resque_jobs_tree/version'
5
5
 
6
6
  Gem::Specification.new do |spec|
7
- spec.name = "resque_jobs_tree"
7
+ spec.name = 'resque_jobs_tree'
8
8
  spec.version = ResqueJobsTree::VERSION
9
- spec.authors = ["Antoine Qu'hen"]
10
- spec.email = ["antoinequhen@gmail.com"]
9
+ spec.authors = ['Antoine Qu\'hen']
10
+ spec.email = ['antoinequhen@gmail.com']
11
11
  spec.description = %q{To manage complexe background job processes, this gem simplify the task of creating sequences of Resque jobs by putting them into a tree.}
12
12
  spec.summary = %q{Organise Resque jobs as a tree.}
13
- spec.homepage = ""
14
- spec.license = "MIT"
13
+ spec.homepage = ''
14
+ spec.license = 'MIT'
15
15
 
16
16
  spec.files = `git ls-files`.split($/)
17
17
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
- spec.require_paths = ["lib"]
19
+ spec.require_paths = ['lib']
20
20
 
21
- spec.add_development_dependency "bundler", "~> 1.3"
22
- spec.add_development_dependency "rake"
21
+ spec.add_development_dependency 'bundler', '~> 1.3'
22
+ spec.add_development_dependency 'rake'
23
23
  spec.add_development_dependency 'minitest'
24
24
  spec.add_development_dependency 'mock_redis'
25
+ spec.add_development_dependency 'mocha'
25
26
  spec.add_dependency 'resque', '~> 1.24'
26
27
  end
@@ -91,7 +91,7 @@ class DefinitionsTest < MiniTest::Unit::TestCase
91
91
  end
92
92
 
93
93
  def test_options
94
- options = { async: true }
94
+ options = { triggerable: true }
95
95
  @leaf.options = options
96
96
  assert_equal options, @tree.find(:node2).options
97
97
  end
data/test/factory_test.rb CHANGED
@@ -14,4 +14,34 @@ class FactoryTest < MiniTest::Unit::TestCase
14
14
  assert_equal ResqueJobsTree::Factory.find(@tree_definition.name).name, @tree_definition.name
15
15
  end
16
16
 
17
+ def test_without_perform_whitout_flag
18
+ assert_raises ResqueJobsTree::NodeDefinitionInvalid do
19
+ ResqueJobsTree::Factory.create :tree_with_job_without_perform do
20
+ root :job_without_perform
21
+ end
22
+ end
23
+ end
24
+
25
+ def test_without_perform
26
+ assert_not_raises do
27
+ ResqueJobsTree::Factory.create :tree_with_job_without_perform do
28
+ # root :job_without_perform, triggerable: true
29
+ root :job_without_perform do
30
+ perform { puts 'job1' }
31
+ childs { [:job1] }
32
+ node :job1 , triggerable: true
33
+ end
34
+ end
35
+ end.must_equal 'ok'
36
+ end
37
+
38
+ def assert_not_raises
39
+ begin
40
+ yield
41
+ 'ok'
42
+ rescue
43
+ raise
44
+ end
45
+ end
46
+
17
47
  end
data/test/process_test.rb CHANGED
@@ -2,10 +2,23 @@ require 'test_helper'
2
2
 
3
3
  class ProcessTest < MiniTest::Unit::TestCase
4
4
 
5
+ def test_launch_without_uniq
6
+ create_tree
7
+ assert_raises ResqueJobsTree::JobNotUniq do
8
+ resque_jobs_tree = @tree_definition.spawn [1, 2, 3]
9
+ resque_jobs_tree.stub :uniq?, false do
10
+ resque_jobs_tree.launch
11
+ end
12
+ end
13
+ end
14
+
5
15
  def test_launch
6
16
  create_tree
7
17
  resources = [1, 2, 3]
8
- @tree_definition.spawn(resources).launch
18
+ resque_jobs_tree = @tree_definition.spawn(resources)
19
+ resque_jobs_tree.stub :uniq?, true do
20
+ resque_jobs_tree.launch
21
+ end
9
22
  history = ['tree1 job2']*3+['tree1 job1']
10
23
  assert_equal history, redis.lrange('history', 0, -1)
11
24
  end
@@ -31,12 +44,29 @@ class ProcessTest < MiniTest::Unit::TestCase
31
44
  assert_redis_empty
32
45
  end
33
46
 
34
- def test_launch_async
47
+ def test_just_one_triggerable_job
48
+ assert_raises ResqueJobsTree::NodeDefinitionInvalid do
49
+ tree_definition = ResqueJobsTree::Factory.create :tree1 do
50
+ root :job1 do
51
+ perform { puts 'job1' }
52
+ childs { [:job2, :job3] }
53
+ node :job2, triggerable: true do
54
+ perform {}
55
+ end
56
+ node :job3, triggerable: true
57
+ end
58
+ end
59
+ tree = tree_definition.spawn [1, 2, 3]
60
+ tree.launch
61
+ end
62
+ end
63
+
64
+ def test_launch_triggerable
35
65
  tree_definition = ResqueJobsTree::Factory.create :tree1 do
36
66
  root :job1 do
37
67
  perform { raise 'should not arrive here' }
38
68
  childs { [:job2] }
39
- node :job2, async: true do
69
+ node :job2, triggerable: true do
40
70
  perform {}
41
71
  end
42
72
  end
@@ -140,9 +170,9 @@ class ProcessTest < MiniTest::Unit::TestCase
140
170
  ResqueJobsTree.launch tree_definition.name, Model.new(1), 1
141
171
  end
142
172
 
143
- def test_nested_tree
173
+ def test_nested_tree_with_job_failure
144
174
  Resque.inline = false
145
- create_nested_tree
175
+ create_nested_tree_with_job_failure
146
176
  @tree_definition.spawn([1,2,3]).launch
147
177
  assert_raises RuntimeError do # job4 error
148
178
  run_resque_workers @tree_definition.name
@@ -157,12 +187,12 @@ class ProcessTest < MiniTest::Unit::TestCase
157
187
  end
158
188
  end
159
189
 
160
- def test_async_tree
190
+ def test_triggerable_tree
161
191
  tree_definition = ResqueJobsTree::Factory.create :tree1 do
162
192
  root :job1 do
163
193
  perform { raise 'should not arrive here' }
164
194
  childs { [ [:job2], [:job3] ] }
165
- node :job2, async: true do
195
+ node :job2, triggerable: true do
166
196
  perform {}
167
197
  end
168
198
  node :job3 do
@@ -177,13 +207,13 @@ class ProcessTest < MiniTest::Unit::TestCase
177
207
  assert_equal parents_hash, Resque.redis.hgetall(ResqueJobsTree::Storage::PARENTS_KEY)
178
208
  end
179
209
 
180
- def test_async_tree_with_fail
210
+ def test_triggerable_tree_with_fail
181
211
  Resque.inline = false
182
212
  tree_definition = ResqueJobsTree::Factory.create :tree1 do
183
213
  root :job1 do
184
214
  perform { raise 'should not arrive here' }
185
215
  childs { [ [:job2], [:job3] ] }
186
- node :job2, async: true do
216
+ node :job2, triggerable: true do
187
217
  perform {}
188
218
  end
189
219
  node :job3, continue_on_failure: true do
data/test/test_helper.rb CHANGED
@@ -70,7 +70,7 @@ class MiniTest::Unit::TestCase
70
70
  end
71
71
  end
72
72
 
73
- def create_nested_tree
73
+ def create_nested_tree_with_job_failure
74
74
  @tree_definition = ResqueJobsTree::Factory.create :tree1 do
75
75
  root :job1 do
76
76
  perform { raise ExpectedException, 'job1' }
@@ -78,7 +78,7 @@ class MiniTest::Unit::TestCase
78
78
  node :job2, continue_on_failure: true do
79
79
  perform { raise 'job2' }
80
80
  childs { [ [:job3], [:job4] ] }
81
- node :job3, async: true do
81
+ node :job3, triggerable: true do
82
82
  perform {}
83
83
  end
84
84
  node :job4, continue_on_failure: true do
data/test/tree_test.rb CHANGED
@@ -10,24 +10,24 @@ class TreeTest < MiniTest::Unit::TestCase
10
10
  assert_equal @tree_definition.name, 'tree1'
11
11
  end
12
12
 
13
- def test_leaves
14
- assert_equal @tree_definition.spawn([]).leaves, []
13
+ def test_nodes
14
+ assert_equal @tree_definition.spawn([]).nodes, []
15
15
  end
16
16
 
17
17
  def test_root
18
18
  assert @tree_definition.root.kind_of? ResqueJobsTree::Definitions::Node
19
19
  end
20
20
 
21
- def test_register_a_leaf
21
+ def test_register_node
22
22
  leaf = 'leaf'
23
23
  tree = @tree_definition.spawn []
24
- tree.register_a_leaf leaf
25
- assert_equal tree.leaves, [leaf]
24
+ tree.register_node leaf
25
+ assert_equal tree.nodes, [leaf]
26
26
  end
27
27
 
28
28
  def test_find
29
29
  assert_equal 'job2', @tree_definition.find(:job2).name
30
- tree_definition = create_nested_tree
30
+ tree_definition = create_nested_tree_with_job_failure
31
31
  assert_equal 'job4', tree_definition.find(:job4).name
32
32
  end
33
33
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: resque_jobs_tree
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.3
4
+ version: 0.5.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-04-25 00:00:00.000000000 Z
12
+ date: 2013-04-30 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -75,6 +75,22 @@ dependencies:
75
75
  - - ! '>='
76
76
  - !ruby/object:Gem::Version
77
77
  version: '0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: mocha
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'
78
94
  - !ruby/object:Gem::Dependency
79
95
  name: resque
80
96
  requirement: !ruby/object:Gem::Requirement