floe 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/floe/workflow.rb CHANGED
@@ -12,9 +12,26 @@ module Floe
12
12
  payload = path_or_io.respond_to?(:read) ? path_or_io.read : File.read(path_or_io)
13
13
  new(payload, context, credentials)
14
14
  end
15
+
16
+ def wait(workflows, timeout: 5)
17
+ logger.info("checking #{workflows.count} workflows...")
18
+
19
+ start = Time.now.utc
20
+ ready = []
21
+
22
+ loop do
23
+ ready = workflows.select(&:step_nonblock_ready?)
24
+ break if timeout.zero? || Time.now.utc - start > timeout || !ready.empty?
25
+
26
+ sleep(1)
27
+ end
28
+
29
+ logger.info("checking #{workflows.count} workflows...Complete - #{ready.count} ready")
30
+ ready
31
+ end
15
32
  end
16
33
 
17
- attr_reader :context, :credentials, :output, :payload, :states, :states_by_name, :current_state, :status
34
+ attr_reader :context, :credentials, :payload, :states, :states_by_name, :start_at
18
35
 
19
36
  def initialize(payload, context = nil, credentials = {})
20
37
  payload = JSON.parse(payload) if payload.kind_of?(String)
@@ -24,62 +41,69 @@ module Floe
24
41
  @payload = payload
25
42
  @context = context
26
43
  @credentials = credentials
44
+ @start_at = payload["StartAt"]
27
45
 
28
46
  @states = payload["States"].to_a.map { |name, state| State.build!(self, name, state) }
29
47
  @states_by_name = @states.each_with_object({}) { |state, result| result[state.name] = state }
30
- start_at = @payload["StartAt"]
31
-
32
- context.state["Name"] ||= start_at
33
-
34
- current_state_name = context.state["Name"]
35
- @current_state = @states_by_name[current_state_name]
36
48
 
37
- @status = current_state_name == start_at ? "pending" : current_state.status
49
+ unless context.state.key?("Name")
50
+ context.state["Name"] = start_at
51
+ context.state["Input"] = context.execution["Input"].dup
52
+ end
38
53
  rescue JSON::ParserError => err
39
54
  raise Floe::InvalidWorkflowError, err.message
40
55
  end
41
56
 
42
- def step
43
- @status = "running" if @status == "pending"
44
- context.execution["StartTime"] ||= Time.now.utc
45
-
46
- context.state["Guid"] = SecureRandom.uuid
47
- context.state["Input"] ||= context.execution["Input"].dup
57
+ def run!
58
+ step until end?
59
+ self
60
+ end
48
61
 
49
- logger.info("Running state: [#{current_state.name}] with input [#{context.state["Input"]}]...")
62
+ def step
63
+ step_nonblock_wait until step_nonblock == 0
64
+ self
65
+ end
50
66
 
51
- context.state["EnteredTime"] = Time.now.utc
67
+ def run_nonblock
68
+ loop while step_nonblock == 0 && !end?
69
+ self
70
+ end
52
71
 
53
- tick = Process.clock_gettime(Process::CLOCK_MONOTONIC)
54
- next_state, output = current_state.run!(context.state["Input"])
55
- tock = Process.clock_gettime(Process::CLOCK_MONOTONIC)
72
+ def step_nonblock
73
+ return Errno::EPERM if end?
56
74
 
57
- context.state["FinishedTime"] = Time.now.utc
58
- context.state["Duration"] = (tock - tick) / 1_000_000.0
59
- context.state["Output"] = output
75
+ step_next
76
+ current_state.run_nonblock!
77
+ end
60
78
 
61
- logger.info("Running state: [#{current_state.name}] with input [#{context["Input"]}]...Complete - next state: [#{next_state}] output: [#{output}]")
79
+ def step_nonblock_wait(timeout: 5)
80
+ current_state.run_wait(:timeout => timeout)
81
+ end
62
82
 
63
- context.states << context.state
83
+ def step_nonblock_ready?
84
+ current_state.ready?
85
+ end
64
86
 
65
- @status = current_state.status
66
- @current_state = next_state && @states_by_name[next_state]
67
- @output = output if end?
87
+ def status
88
+ context.status
89
+ end
68
90
 
69
- context.state = {"Name" => next_state, "Input" => output} unless end?
91
+ def output
92
+ context.output if end?
93
+ end
70
94
 
71
- self
95
+ def end?
96
+ context.ended?
72
97
  end
73
98
 
74
- def run!
75
- until end?
76
- step
77
- end
78
- self
99
+ def current_state
100
+ @states_by_name[context.state_name]
79
101
  end
80
102
 
81
- def end?
82
- current_state.nil?
103
+ private
104
+
105
+ def step_next
106
+ context.state = {"Name" => context.next_state, "Input" => context.output} if context.next_state
83
107
  end
84
108
  end
85
109
  end
data/lib/floe.rb CHANGED
@@ -8,7 +8,9 @@ require_relative "floe/logging"
8
8
  require_relative "floe/workflow"
9
9
  require_relative "floe/workflow/catcher"
10
10
  require_relative "floe/workflow/choice_rule"
11
- require_relative "floe/workflow/choice_rule/boolean"
11
+ require_relative "floe/workflow/choice_rule/not"
12
+ require_relative "floe/workflow/choice_rule/or"
13
+ require_relative "floe/workflow/choice_rule/and"
12
14
  require_relative "floe/workflow/choice_rule/data"
13
15
  require_relative "floe/workflow/context"
14
16
  require_relative "floe/workflow/path"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: floe
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - ManageIQ Developers
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-08-07 00:00:00.000000000 Z
11
+ date: 2023-09-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: awesome_spawn
@@ -80,48 +80,6 @@ dependencies:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
82
  version: '3.0'
83
- - !ruby/object:Gem::Dependency
84
- name: manageiq-style
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - ">="
88
- - !ruby/object:Gem::Version
89
- version: '0'
90
- type: :development
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - ">="
95
- - !ruby/object:Gem::Version
96
- version: '0'
97
- - !ruby/object:Gem::Dependency
98
- name: rspec
99
- requirement: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - ">="
102
- - !ruby/object:Gem::Version
103
- version: '0'
104
- type: :development
105
- prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - ">="
109
- - !ruby/object:Gem::Version
110
- version: '0'
111
- - !ruby/object:Gem::Dependency
112
- name: rubocop
113
- requirement: !ruby/object:Gem::Requirement
114
- requirements:
115
- - - ">="
116
- - !ruby/object:Gem::Version
117
- version: '0'
118
- type: :development
119
- prerelease: false
120
- version_requirements: !ruby/object:Gem::Requirement
121
- requirements:
122
- - - ">="
123
- - !ruby/object:Gem::Version
124
- version: '0'
125
83
  description: Simple Workflow Runner.
126
84
  email:
127
85
  executables:
@@ -148,8 +106,10 @@ files:
148
106
  - lib/floe/workflow.rb
149
107
  - lib/floe/workflow/catcher.rb
150
108
  - lib/floe/workflow/choice_rule.rb
151
- - lib/floe/workflow/choice_rule/boolean.rb
109
+ - lib/floe/workflow/choice_rule/and.rb
152
110
  - lib/floe/workflow/choice_rule/data.rb
111
+ - lib/floe/workflow/choice_rule/not.rb
112
+ - lib/floe/workflow/choice_rule/or.rb
153
113
  - lib/floe/workflow/context.rb
154
114
  - lib/floe/workflow/path.rb
155
115
  - lib/floe/workflow/payload_template.rb
@@ -1,19 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Floe
4
- class Workflow
5
- class ChoiceRule
6
- class Boolean < Floe::Workflow::ChoiceRule
7
- def true?(context, input)
8
- if payload.key?("Not")
9
- !ChoiceRule.true?(payload["Not"], context, input)
10
- elsif payload.key?("And")
11
- payload["And"].all? { |choice| ChoiceRule.true?(choice, context, input) }
12
- else
13
- payload["Or"].any? { |choice| ChoiceRule.true?(choice, context, input) }
14
- end
15
- end
16
- end
17
- end
18
- end
19
- end