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.
- checksums.yaml +5 -5
- data/.ruby-version +1 -1
- data/Gemfile +2 -0
- data/Rakefile +3 -1
- data/bin/console +1 -0
- data/lib/swarm/engine/{base/job.rb → job.rb} +2 -0
- data/lib/swarm/engine/{base/queue.rb → queue.rb} +7 -5
- data/lib/swarm/engine/volatile/job.rb +6 -2
- data/lib/swarm/engine/volatile/queue.rb +7 -4
- data/lib/swarm/engine/worker/command.rb +5 -1
- data/lib/swarm/engine/worker.rb +22 -19
- data/lib/swarm/evaluation/expression_evaluator.rb +21 -14
- data/lib/swarm/expression.rb +8 -6
- data/lib/swarm/expressions/activity_expression.rb +2 -0
- data/lib/swarm/expressions/branch_expression.rb +12 -9
- data/lib/swarm/expressions/concurrence_expression.rb +8 -5
- data/lib/swarm/expressions/conditional_expression.rb +4 -2
- data/lib/swarm/expressions/sequence_expression.rb +4 -2
- data/lib/swarm/expressions/subprocess_expression.rb +4 -1
- data/lib/swarm/hive.rb +9 -16
- data/lib/swarm/hive_dweller.rb +69 -38
- data/lib/swarm/observers/base.rb +3 -1
- data/lib/swarm/observers/logger.rb +40 -0
- data/lib/swarm/participant.rb +3 -1
- data/lib/swarm/participants/storage_participant.rb +6 -4
- data/lib/swarm/participants/trace_participant.rb +2 -0
- data/lib/swarm/pollen/parser.rb +48 -44
- data/lib/swarm/pollen/reader.rb +5 -3
- data/lib/swarm/pollen/transformer.rb +30 -24
- data/lib/swarm/process.rb +21 -14
- data/lib/swarm/process_definition.rb +13 -10
- data/lib/swarm/router.rb +8 -6
- data/lib/swarm/storage/hash_storage.rb +3 -1
- data/lib/swarm/storage/key_value_storage.rb +27 -13
- data/lib/swarm/storage/redis_storage.rb +4 -2
- data/lib/swarm/storage.rb +3 -1
- data/lib/swarm/stored_workitem.rb +4 -2
- data/lib/swarm/support.rb +13 -16
- data/lib/swarm/version.rb +3 -1
- data/lib/swarm.rb +4 -2
- data/swarm.gemspec +7 -5
- metadata +51 -24
- data/lib/swarm/evaluation/workitem_context.rb +0 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 2710e2cf0320ab75ec855436418e709f58f8fae599e252c34e1f67627486d957
|
4
|
+
data.tar.gz: cc6875174915cf2d6cda654330cbf928fb232cccbb539e49cc6906f54fb7ffc5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fb07523f65ce4342d8da7f64589f32f04ef003256e7f4f528a14922ffc39857cdffd4a998f97e250381251bf384b9a202a76e89abb5737dc62c6c8f4afe60cec
|
7
|
+
data.tar.gz: f8fc5e6f34d260e383a3591305b9d779ff9b74ca16f8eda29458c49cf14c4d43cf27afc8c36429c1f7b1f04ab02f88986d82425bcbb068b8ee6421da9918865d
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
3.3.
|
data/Gemfile
CHANGED
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 :
|
13
|
+
task default: [:spec]
|
12
14
|
|
13
15
|
Rake::TaskManager.record_task_metadata = true
|
data/bin/console
CHANGED
@@ -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(
|
17
|
+
def prepare_for_work(_worker)
|
16
18
|
raise "Not implemented yet!"
|
17
19
|
end
|
18
20
|
|
19
|
-
def add_job(
|
21
|
+
def add_job(_data)
|
20
22
|
raise "Not implemented yet!"
|
21
23
|
end
|
22
24
|
|
23
|
-
def reserve_job(
|
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(
|
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.
|
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
|
-
|
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
|
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
|
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
|
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
|
data/lib/swarm/engine/worker.rb
CHANGED
@@ -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
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
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, :
|
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
|
-
|
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
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
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,
|
24
|
-
check_condition(type,
|
29
|
+
conditions.all? { |type, condition|
|
30
|
+
check_condition(type, condition)
|
25
31
|
}
|
26
32
|
end
|
27
33
|
|
28
|
-
def check_condition(type,
|
29
|
-
unless [
|
30
|
-
raise ArgumentError
|
34
|
+
def check_condition(type, condition)
|
35
|
+
unless %w[if unless].include?(type)
|
36
|
+
raise ArgumentError, "Not a conditional"
|
31
37
|
end
|
32
|
-
|
38
|
+
|
39
|
+
result = evaluate_condition(condition)
|
33
40
|
type == "if" ? result : !result
|
34
41
|
end
|
35
42
|
|
36
43
|
def conditions
|
37
|
-
|
44
|
+
arguments.slice("if", "unless")
|
38
45
|
end
|
39
46
|
end
|
40
47
|
end
|
data/lib/swarm/expression.rb
CHANGED
@@ -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
|
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, :
|
18
|
-
many_to_one :parent, :
|
19
|
-
one_to_many :children, :
|
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
|
-
|
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,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
|
-
(
|
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
|
-
|
30
|
-
:
|
31
|
-
:
|
32
|
-
:
|
33
|
-
:
|
34
|
-
:
|
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
|
-
|
27
|
-
|
28
|
-
|
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, :
|
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
|
-
|
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
|
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
|
-
|
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
|
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
|
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
|
-
:
|
53
|
-
:
|
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
|