swarm 0.3.0 → 0.4.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 (43) hide show
  1. checksums.yaml +5 -5
  2. data/.ruby-version +1 -1
  3. data/Gemfile +2 -0
  4. data/Rakefile +3 -1
  5. data/bin/console +1 -0
  6. data/lib/swarm/engine/{base/job.rb → job.rb} +2 -0
  7. data/lib/swarm/engine/{base/queue.rb → queue.rb} +7 -5
  8. data/lib/swarm/engine/volatile/job.rb +6 -2
  9. data/lib/swarm/engine/volatile/queue.rb +7 -4
  10. data/lib/swarm/engine/worker/command.rb +5 -1
  11. data/lib/swarm/engine/worker.rb +22 -19
  12. data/lib/swarm/evaluation/expression_evaluator.rb +21 -14
  13. data/lib/swarm/expression.rb +8 -6
  14. data/lib/swarm/expressions/activity_expression.rb +2 -0
  15. data/lib/swarm/expressions/branch_expression.rb +12 -9
  16. data/lib/swarm/expressions/concurrence_expression.rb +8 -5
  17. data/lib/swarm/expressions/conditional_expression.rb +4 -2
  18. data/lib/swarm/expressions/sequence_expression.rb +4 -2
  19. data/lib/swarm/expressions/subprocess_expression.rb +4 -1
  20. data/lib/swarm/hive.rb +9 -16
  21. data/lib/swarm/hive_dweller.rb +69 -38
  22. data/lib/swarm/observers/base.rb +3 -1
  23. data/lib/swarm/observers/logger.rb +40 -0
  24. data/lib/swarm/participant.rb +3 -1
  25. data/lib/swarm/participants/storage_participant.rb +6 -4
  26. data/lib/swarm/participants/trace_participant.rb +2 -0
  27. data/lib/swarm/pollen/parser.rb +48 -44
  28. data/lib/swarm/pollen/reader.rb +5 -3
  29. data/lib/swarm/pollen/transformer.rb +30 -24
  30. data/lib/swarm/process.rb +21 -14
  31. data/lib/swarm/process_definition.rb +13 -10
  32. data/lib/swarm/router.rb +8 -6
  33. data/lib/swarm/storage/hash_storage.rb +3 -1
  34. data/lib/swarm/storage/key_value_storage.rb +27 -13
  35. data/lib/swarm/storage/redis_storage.rb +4 -2
  36. data/lib/swarm/storage.rb +3 -1
  37. data/lib/swarm/stored_workitem.rb +4 -2
  38. data/lib/swarm/support.rb +13 -16
  39. data/lib/swarm/version.rb +3 -1
  40. data/lib/swarm.rb +4 -2
  41. data/swarm.gemspec +7 -5
  42. metadata +51 -24
  43. data/lib/swarm/evaluation/workitem_context.rb +0 -17
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: e4410067eb9ac5847b4add5e8a31f9c78f3a6f18
4
- data.tar.gz: fdf564f1018be4d4ffdd837777c4fd25d1a1664d
2
+ SHA256:
3
+ metadata.gz: 2710e2cf0320ab75ec855436418e709f58f8fae599e252c34e1f67627486d957
4
+ data.tar.gz: cc6875174915cf2d6cda654330cbf928fb232cccbb539e49cc6906f54fb7ffc5
5
5
  SHA512:
6
- metadata.gz: 02303d2b8f04002bad616eddbd69ecec4e49f33cd44b4b3785802147c4815ad4f52e318c267a4f7f2de5be8451de48567b01a0ccdb277cfac7b88c140b716a94
7
- data.tar.gz: ab727019332409f4e5954f8c23c34b62c1b445497b107b60f58d1c12d6fb76e5bc35c1195c0241983dabe9002ef2db007862ebbf24420a87f45dd3cc90fb4b01
6
+ metadata.gz: fb07523f65ce4342d8da7f64589f32f04ef003256e7f4f528a14922ffc39857cdffd4a998f97e250381251bf384b9a202a76e89abb5737dc62c6c8f4afe60cec
7
+ data.tar.gz: f8fc5e6f34d260e383a3591305b9d779ff9b74ca16f8eda29458c49cf14c4d43cf27afc8c36429c1f7b1f04ab02f88986d82425bcbb068b8ee6421da9918865d
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 2.1.
1
+ 3.3.
data/Gemfile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  source 'https://rubygems.org'
2
4
 
3
5
  # Specify your gem's dependencies in swarm.gemspec
data/Rakefile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "bundler/gem_tasks"
2
4
 
3
5
  require 'rspec/core/rake_task'
@@ -8,6 +10,6 @@ RSpec::Core::RakeTask.new(:spec, :tag) do |t, task_args|
8
10
  end
9
11
  end
10
12
 
11
- task :default => [:spec]
13
+ task default: [:spec]
12
14
 
13
15
  Rake::TaskManager.record_task_metadata = true
data/bin/console CHANGED
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
4
  require "bundler/setup"
4
5
  require "swarm"
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Swarm
2
4
  module Engine
3
5
  class Job
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative "job"
2
4
 
3
5
  module Swarm
@@ -12,15 +14,15 @@ module Swarm
12
14
  @name = name
13
15
  end
14
16
 
15
- def prepare_for_work(worker)
17
+ def prepare_for_work(_worker)
16
18
  raise "Not implemented yet!"
17
19
  end
18
20
 
19
- def add_job(data)
21
+ def add_job(_data)
20
22
  raise "Not implemented yet!"
21
23
  end
22
24
 
23
- def reserve_job(worker)
25
+ def reserve_job(_worker)
24
26
  raise "Not implemented yet!"
25
27
  end
26
28
 
@@ -36,7 +38,7 @@ module Swarm
36
38
  job.bury if job.exists? && job.reserved?
37
39
  end
38
40
 
39
- def remove_worker(worker, stop_job:)
41
+ def remove_worker(_worker, stop_job:)
40
42
  if worker_count <= 1
41
43
  stop_job.delete
42
44
  else
@@ -57,4 +59,4 @@ module Swarm
57
59
  end
58
60
  end
59
61
  end
60
- end
62
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Swarm
2
4
  module Engine
3
5
  module Volatile
@@ -5,6 +7,7 @@ module Swarm
5
7
  attr_reader :queue, :data, :id, :reserved_by, :buried
6
8
 
7
9
  def initialize(queue:, data:)
10
+ super()
8
11
  @queue = queue
9
12
  @data = data
10
13
  @id = SecureRandom.uuid
@@ -25,6 +28,7 @@ module Swarm
25
28
  if reserved_by && reserved_by != worker
26
29
  raise AlreadyReservedError
27
30
  end
31
+
28
32
  @reserved_by = worker
29
33
  end
30
34
 
@@ -49,9 +53,9 @@ module Swarm
49
53
  end
50
54
 
51
55
  def exists?
52
- queue.has_job?(self)
56
+ queue.job_exists?(self)
53
57
  end
54
58
  end
55
59
  end
56
60
  end
57
- end
61
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative "job"
2
4
 
3
5
  module Swarm
@@ -22,7 +24,7 @@ module Swarm
22
24
  end
23
25
 
24
26
  def initialize(name:)
25
- @name = name
27
+ super
26
28
  @tube = self.class.get_tube(name)
27
29
  end
28
30
 
@@ -47,8 +49,9 @@ module Swarm
47
49
 
48
50
  def reserve_job(worker)
49
51
  wait_for_job
50
- index = jobs.index { |job| job.available? }
52
+ index = jobs.index(&:available?)
51
53
  raise JobNotFoundError unless index
54
+
52
55
  job = jobs[index]
53
56
  job.reserve!(worker)
54
57
  job
@@ -60,7 +63,7 @@ module Swarm
60
63
  jobs.delete_if { |job| job == job_to_delete }
61
64
  end
62
65
 
63
- def has_job?(job_to_find)
66
+ def job_exists?(job_to_find)
64
67
  jobs.any? { |job| job == job_to_find }
65
68
  end
66
69
 
@@ -82,4 +85,4 @@ module Swarm
82
85
  end
83
86
  end
84
87
  end
85
- end
88
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Swarm
2
4
  module Engine
3
5
  class Worker
@@ -14,7 +16,7 @@ module Swarm
14
16
 
15
17
  attr_reader :action, :metadata, :hive
16
18
 
17
- def initialize(hive: Hive.default, action:, metadata:)
19
+ def initialize(action:, metadata:, hive: Hive.default)
18
20
  @hive = hive
19
21
  @action = action
20
22
  @metadata = Swarm::Support.symbolize_keys(metadata || {})
@@ -22,6 +24,7 @@ module Swarm
22
24
 
23
25
  def run!
24
26
  raise MissingObjectError if object.nil?
27
+
25
28
  observers.each(&:before_action)
26
29
  object.send("_#{action}")
27
30
  observers.each(&:after_action)
@@ -36,6 +39,7 @@ module Swarm
36
39
  def object
37
40
  @object ||= begin
38
41
  return nil unless metadata[:type] && metadata[:id]
42
+
39
43
  hive.fetch(metadata[:type], metadata[:id])
40
44
  end
41
45
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative "worker/command"
2
4
 
3
5
  module Swarm
@@ -22,27 +24,27 @@ module Swarm
22
24
  def run!
23
25
  setup
24
26
  @running = true
25
- while running?
26
- process_next_job
27
- end
27
+ process_next_job while running?
28
28
  teardown
29
29
  end
30
30
 
31
31
  def process_next_job
32
- begin
33
- @current_job = queue.reserve_job(self)
34
- @working = true
35
- work_on(@current_job)
36
- queue.delete_job(@current_job) if @current_job
37
- rescue Queue::JobReservationFailed
38
- retry
39
- rescue StandardError
40
- queue.bury_job(@current_job) if @current_job
41
- ensure
42
- queue.clean_up_job(@current_job) if @current_job
43
- @working = false
44
- @current_job = nil
45
- end
32
+ @current_job = queue.reserve_job(self)
33
+ @working = true
34
+ work_on(@current_job)
35
+ queue.delete_job(@current_job) if @current_job
36
+ rescue Queue::JobReservationFailed
37
+ retry
38
+ rescue StandardError
39
+ queue.bury_job(@current_job) if @current_job
40
+ ensure
41
+ cleanup!
42
+ end
43
+
44
+ def cleanup!
45
+ queue.clean_up_job(@current_job) if @current_job
46
+ @working = false
47
+ @current_job = nil
46
48
  end
47
49
 
48
50
  def working?
@@ -60,9 +62,10 @@ module Swarm
60
62
 
61
63
  def work_on(queue_job)
62
64
  raise NotRunningError unless running?
65
+
63
66
  command = Command.from_job(queue_job, hive: hive)
64
67
  if command.stop?
65
- queue.remove_worker(self, :stop_job => queue_job)
68
+ queue.remove_worker(self, stop_job: queue_job)
66
69
  stop!
67
70
  else
68
71
  command.run!
@@ -70,4 +73,4 @@ module Swarm
70
73
  end
71
74
  end
72
75
  end
73
- end
76
+ end
@@ -1,40 +1,47 @@
1
- require_relative "workitem_context"
1
+ # frozen_string_literal: true
2
+
3
+ require "dentaku"
2
4
 
3
5
  module Swarm
4
6
  class ExpressionEvaluator
7
+ class UndefinedExpressionVariableError < StandardError; end
8
+ class InvalidExpressionError < StandardError; end
9
+
5
10
  extend Forwardable
6
11
 
7
12
  attr_reader :expression
13
+
8
14
  def_delegators :expression, :workitem, :arguments
9
15
 
10
16
  def initialize(expression)
11
17
  @expression = expression
12
18
  end
13
19
 
14
- def workitem_context
15
- @workitem_context ||= WorkitemContext.new(workitem)
16
- end
17
-
18
- def eval(string)
19
- workitem_context.instance_eval(string)
20
+ def evaluate_condition(string)
21
+ Dentaku.evaluate!(string, workitem)
22
+ rescue Dentaku::UnboundVariableError => e
23
+ raise UndefinedExpressionVariableError, e
24
+ rescue Dentaku::Error => e
25
+ raise InvalidExpressionError, e
20
26
  end
21
27
 
22
28
  def all_conditions_met?
23
- conditions.all? { |type, exp|
24
- check_condition(type, exp)
29
+ conditions.all? { |type, condition|
30
+ check_condition(type, condition)
25
31
  }
26
32
  end
27
33
 
28
- def check_condition(type, exp)
29
- unless ["if", "unless"].include?(type)
30
- raise ArgumentError.new("Not a conditional")
34
+ def check_condition(type, condition)
35
+ unless %w[if unless].include?(type)
36
+ raise ArgumentError, "Not a conditional"
31
37
  end
32
- result = eval(exp)
38
+
39
+ result = evaluate_condition(condition)
33
40
  type == "if" ? result : !result
34
41
  end
35
42
 
36
43
  def conditions
37
- Swarm::Support.slice(arguments, "if", "unless")
44
+ arguments.slice("if", "unless")
38
45
  end
39
46
  end
40
47
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative "evaluation/expression_evaluator"
2
4
 
3
5
  module Swarm
@@ -9,14 +11,14 @@ module Swarm
9
11
 
10
12
  def inherited(subclass)
11
13
  super
12
- subclass.set_columns *columns
14
+ subclass.set_columns(*columns)
13
15
  end
14
16
  end
15
17
 
16
18
  set_columns :parent_id, :position, :workitem, :children_ids, :milestones, :process_id
17
- many_to_one :process, :class_name => "Swarm::Process"
18
- many_to_one :parent, :class_name => "Swarm::Expression", :key => :parent_id
19
- one_to_many :children, :class_name => "Swarm::Expression", :foreign_key => :parent_id
19
+ many_to_one :process, class_name: "Swarm::Process"
20
+ many_to_one :parent, class_name: "Swarm::Expression", key: :parent_id
21
+ one_to_many :children, class_name: "Swarm::Expression", foreign_key: :parent_id
20
22
 
21
23
  def branch_position
22
24
  @branch_position ||= position.last
@@ -96,7 +98,7 @@ module Swarm
96
98
  tree[position]
97
99
  end
98
100
 
99
- private
101
+ private
100
102
 
101
103
  def set_milestone(name, at: Time.now.to_i)
102
104
  self.milestones = (milestones || {}).merge(name => at)
@@ -106,4 +108,4 @@ module Swarm
106
108
  (milestones || {})[name]
107
109
  end
108
110
  end
109
- end
111
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Swarm
2
4
  class ActivityExpression < Expression
3
5
  def work
@@ -1,8 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative "../router"
2
4
 
3
5
  module Swarm
4
6
  class BranchExpression < Expression
5
- class InvalidPositionError < StandardError; end;
7
+ class InvalidPositionError < StandardError; end
6
8
 
7
9
  def kick_off_children(at_positions)
8
10
  at_positions.each do |at_position|
@@ -19,20 +21,21 @@ module Swarm
19
21
  def add_child(at_position)
20
22
  node = tree[at_position]
21
23
  raise InvalidPositionError unless node
24
+
22
25
  expression = create_child_expression(node: node, at_position: at_position)
23
- (self.children_ids ||= []) << expression.id
26
+ add_to_children(expression)
24
27
  expression
25
28
  end
26
29
 
27
30
  def create_child_expression(node:, at_position:)
28
31
  klass = Router.expression_class_for_node(node)
29
- expression = klass.create(
30
- :hive => hive,
31
- :parent_id => id,
32
- :position => position + [at_position],
33
- :workitem => workitem,
34
- :process_id => process_id
32
+ klass.create(
33
+ hive: hive,
34
+ parent_id: id,
35
+ position: position + [at_position],
36
+ workitem: workitem,
37
+ process_id: process_id
35
38
  )
36
39
  end
37
40
  end
38
- end
41
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative "branch_expression"
2
4
 
3
5
  module Swarm
@@ -13,6 +15,7 @@ module Swarm
13
15
  def ready_to_proceed?
14
16
  required_replies = arguments.fetch("required_replies", nil)
15
17
  return all_children_replied? unless required_replies
18
+
16
19
  replied_children.count >= required_replies
17
20
  end
18
21
 
@@ -23,14 +26,14 @@ module Swarm
23
26
  def move_on_from(child)
24
27
  merge_child_workitem(child)
25
28
  save
26
- if all_children_replied?
27
- reply
28
- end
29
+ return unless all_children_replied?
30
+
31
+ reply
29
32
  end
30
33
 
31
34
  def merge_child_workitem(child)
32
35
  self.workitem = Swarm::Support.deep_merge(
33
- workitem, child.workitem, :combine_arrays => array_combination_method
36
+ workitem, child.workitem, combine_arrays: array_combination_method
34
37
  )
35
38
  end
36
39
 
@@ -38,4 +41,4 @@ module Swarm
38
41
  arguments.fetch("combine_arrays", "uniq")
39
42
  end
40
43
  end
41
- end
44
+ end
@@ -1,8 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative "branch_expression"
2
4
 
3
5
  module Swarm
4
6
  class ConditionalExpression < BranchExpression
5
- alias_method :original_tree, :tree
7
+ alias original_tree tree
6
8
 
7
9
  def work
8
10
  if tree.empty?
@@ -33,4 +35,4 @@ module Swarm
33
35
  evaluator.check_condition(command, arguments["condition"])
34
36
  end
35
37
  end
36
- end
38
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative "branch_expression"
2
4
 
3
5
  module Swarm
@@ -9,8 +11,8 @@ module Swarm
9
11
  def move_on_from(child)
10
12
  self.workitem = child.workitem
11
13
  kick_off_children([child.branch_position + 1])
12
- rescue InvalidPositionError => e
14
+ rescue InvalidPositionError
13
15
  reply
14
16
  end
15
17
  end
16
- end
18
+ end
@@ -1,9 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Swarm
2
4
  class SubprocessExpression < Expression
3
5
  def work
4
6
  definition = ProcessDefinition.find_by_name(arguments.fetch("name", nil))
5
7
  raise Swarm::ProcessDefinition::RecordNotFoundError unless definition
6
- process = definition.launch_process(workitem: workitem, parent_expression_id: id)
8
+
9
+ definition.launch_process(workitem: workitem, parent_expression_id: id)
7
10
  end
8
11
 
9
12
  def move_on_from(process)
data/lib/swarm/hive.rb CHANGED
@@ -1,21 +1,24 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Swarm
2
4
  class Hive
3
- class MissingTypeError < StandardError; end
4
5
  class IllegalDefaultError < StandardError; end
5
6
  class NoDefaultSetError < StandardError; end
6
7
 
7
8
  class << self
8
9
  def default=(default)
9
10
  unless default.is_a?(self)
10
- raise IllegalDefaultError.new("Default must be a Swarm::Hive")
11
+ raise IllegalDefaultError, "Default must be a Swarm::Hive"
11
12
  end
13
+
12
14
  @default = default
13
15
  end
14
16
 
15
17
  def default
16
18
  unless @default
17
- raise NoDefaultSetError.new("No default Hive defined yet")
19
+ raise NoDefaultSetError, "No default Hive defined yet"
18
20
  end
21
+
19
22
  @default
20
23
  end
21
24
  end
@@ -49,23 +52,13 @@ module Swarm
49
52
 
50
53
  def queue(action, object)
51
54
  @work_queue.add_job({
52
- :action => action,
53
- :metadata => object.to_hash
55
+ action: action,
56
+ metadata: object.to_hash
54
57
  })
55
58
  end
56
59
 
57
60
  def fetch(klass, id)
58
61
  Swarm::Support.constantize(klass).fetch(id, hive: self)
59
62
  end
60
-
61
- def reify_from_hash(hsh)
62
- Support.symbolize_keys!(hsh)
63
- raise MissingTypeError.new(hsh.inspect) unless hsh[:type]
64
- Swarm::Support.constantize(hsh.delete(:type)).new_from_storage(
65
- hsh.merge(
66
- :hive => self
67
- )
68
- )
69
- end
70
63
  end
71
- end
64
+ end