oflow 0.6.0 → 0.8.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.
@@ -1,214 +0,0 @@
1
-
2
- module OFlow
3
-
4
- # Provides the ability to have Tasks and Flows.
5
- module HasTasks
6
-
7
- # Initializes the tasks attribute.
8
- def init_tasks()
9
- @tasks = {}
10
- end
11
-
12
- # Creates a Flow and yield to a block with the newly create Flow. Used to
13
- # contruct Flows.
14
- # @param name [Symbol|String] base name for the Flow
15
- # @param options [Hash] optional parameters
16
- # @param block [Proc] block to yield to with the new Flow instance
17
- # @return [Flow] new Flow
18
- def flow(name, options={}, &block)
19
- f = Flow.new(self, name, options)
20
- @tasks[f.name] = f
21
- yield(f) if block_given?
22
- f.resolve_all_links()
23
- # Wait to validate until at the top so up-links don't fail validation.
24
- if Env == self
25
- f.validate()
26
- f.start()
27
- end
28
- f
29
- end
30
-
31
- # Creates a Task and yield to a block with the newly create Task. Used to
32
- # configure Tasks.
33
- # @param name [Symbol|String] base name for the Task
34
- # @param actor_class [Class] Class to create an Actor instance of
35
- # @param options [Hash] optional parameters
36
- # @param block [Proc] block to yield to with the new Task instance
37
- # @return [Task] new Task
38
- def task(name, actor_class, options={}, &block)
39
- has_state = options.has_key?(:state)
40
- options[:state] = Task::STOPPED unless has_state
41
- t = Task.new(self, name, actor_class, options)
42
- @tasks[t.name] = t
43
- yield(t) if block_given?
44
- t
45
- end
46
-
47
- # Validates the container by verifying all links on a task have been set to
48
- # a valid destination and that destination has been resolved.
49
- # @raise [ValidateError] if there is an error in validation
50
- def validate()
51
- # collects errors and raises all errors at once if there are any
52
- errors = _validation_errors()
53
- raise ValidateError.new(errors) unless errors.empty?
54
- end
55
-
56
- # Returns an Array of validation errors.
57
- def _validation_errors()
58
- errors = []
59
- @tasks.each_value { |t| errors += t._validation_errors() }
60
- errors
61
- end
62
-
63
- # Resolves all the Links on all the Tasks and Flows being managed as well as
64
- # any Links in the instance itself.
65
- def resolve_all_links()
66
- @links.each_value { |lnk|
67
- set_link_target(lnk) if lnk.target.nil?
68
- }
69
- @tasks.each_value { |t|
70
- t.resolve_all_links()
71
- }
72
- end
73
-
74
- # Iterates over each Task and yields to the provided block with each Task.
75
- # @param blk [Proc] Proc to call on each iteration
76
- def each_task(&blk)
77
- @tasks.each { |name,task| blk.yield(task) }
78
- end
79
-
80
- # Performs a recursive walk over all Tasks and yields to the provided block
81
- # for each. Flows are followed recusively.
82
- # @param tasks_only [true|false] indicates on Tasks and not Flows are yielded to
83
- # @param blk [Proc] Proc to call on each iteration
84
- def walk_tasks(tasks_only=true, &blk)
85
- @tasks.each_value do |t|
86
- if t.is_a?(Task)
87
- blk.yield(t)
88
- else
89
- blk.yield(t) unless tasks_only
90
- t.walk_tasks(tasks_only, &blk)
91
- end
92
- end
93
- end
94
-
95
- # Locates and return a Task with the specified name.
96
- # @param name [String] name of the Task
97
- # @return [Task|nil] the Task with the name specified or nil
98
- def find_task(name)
99
- name = name.to_sym unless name.nil?
100
- return self if :flow == name
101
- @tasks[name]
102
- end
103
-
104
- # Locates and return a Task with the specified full name.
105
- # @param name [String] full name of the Task
106
- # @return [Task|nil] the Task with the name specified or nil
107
- def locate(name)
108
- name = name[1..-1] if name.start_with?(':')
109
- name = name[0..-2] if name.end_with?(':')
110
- path = name.split(':')
111
- _locate(path)
112
- end
113
-
114
- def _locate(path)
115
- t = @tasks[path[0].to_sym]
116
- return t if t.nil? || 1 == path.size
117
- t._locate(path[1..-1])
118
- end
119
-
120
- # Returns the number of active Tasks.
121
- def task_count()
122
- @tasks.size
123
- end
124
-
125
- # Returns the sum of all the requests in all the Tasks's queues.
126
- # @return [Fixnum] total number of items waiting to be processed
127
- def queue_count()
128
- cnt = 0
129
- @tasks.each_value { |task| cnt += task.queue_count() }
130
- cnt
131
- end
132
-
133
- # Returns true of one or more Tasks is either processing a request or has a
134
- # request waiting to be processed on it's input queue.
135
- # @return [true|false] the busy state across all Tasks
136
- def busy?
137
- @tasks.each_value { |task| return true if task.busy? }
138
- false
139
- end
140
-
141
- # Calls the stop() method on all Tasks.
142
- def stop()
143
- @tasks.each_value { |task| task.stop() }
144
- end
145
-
146
- # Calls the step() method one Task that is stopped and has an item in the
147
- # queue. The Tasks with the highest backed_up() value is selected.
148
- def step()
149
- max = 0.0
150
- best = nil
151
- walk_tasks() do |t|
152
- if Task::STOPPED == t.state
153
- bu = t.backed_up()
154
- if max < bu
155
- best = t
156
- max = bu
157
- end
158
- end
159
- end
160
- best.step() unless best.nil?
161
- best
162
- end
163
-
164
- # Calls the start() method on all Tasks.
165
- def start()
166
- @tasks.each_value { |task| task.start() }
167
- end
168
-
169
- # Wakes up all the Tasks in the Flow.
170
- def wakeup()
171
- @tasks.each_value { |t| t.wakeup() }
172
- end
173
-
174
- # Wakes up all the Tasks in the Flow and waits for the system to become idle
175
- # before returning.
176
- def flush()
177
- wakeup()
178
- @tasks.each_value { |t| t.flush() }
179
- while busy?
180
- sleep(0.2)
181
- end
182
- end
183
-
184
- # Sets the state of all Tasks recursively. This should not be called
185
- # directly.
186
- def state=(s)
187
- @tasks.each_value do |task|
188
- task.state = s
189
- end
190
- end
191
-
192
- # Shuts down all Tasks.
193
- # @param flush_first [true|false] flag indicating shutdown should occur after the system becomes idle
194
- def shutdown(flush_first=false)
195
- # block all tasks first so threads can empty queues
196
- @tasks.each_value do |task|
197
- task.state = Task::BLOCKED
198
- end
199
- # shutdown and wait for queues to empty if necessary
200
- @tasks.each_value do |task|
201
- task.shutdown(flush_first)
202
- end
203
- @tasks = {}
204
- end
205
-
206
- # Clears out all Tasks and Flows and resets the object back to a empty state.
207
- def clear()
208
- shutdown()
209
- @tasks = {}
210
- _clear()
211
- end
212
-
213
- end # HasTasks
214
- end # OFlow
@@ -1,215 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # encoding: UTF-8
3
-
4
- [ File.dirname(__FILE__),
5
- File.join(File.dirname(__FILE__), "../lib")
6
- ].each { |path| $: << path unless $:.include?(path) }
7
-
8
- require 'test/unit'
9
- require 'oflow'
10
-
11
- require 'collector'
12
-
13
- class Hop < ::OFlow::Actor
14
-
15
- def initialize(task, options)
16
- super
17
- end
18
-
19
- def perform(op, box)
20
- task.warn("#{op} #{box.contents}")
21
- task.ship(op, box)
22
- end
23
-
24
- end # Hop
25
-
26
- class FlowNestTest < ::Test::Unit::TestCase
27
-
28
- def test_flow_nest
29
- trigger = nil
30
- collector = nil
31
- ::OFlow::Env.flow(:nest, :opt1 => 1) { |f|
32
- # use collector as the log
33
- f.task(:log, Collector) { |t|
34
- collector = t.actor
35
- }
36
-
37
- # starts off the process
38
- trigger = f.task(:trigger, Hop) { |t|
39
- t.link(nil, :deep, nil)
40
- }
41
- # a nested flow
42
- f.flow(:deep) { |f2|
43
- f2.route(nil, :one, nil)
44
- f2.task(:one, Hop) { |t|
45
- t.link(nil, :two, nil)
46
- }
47
- f2.task(:two, Hop) { |t|
48
- t.link(nil, :flow, :bye)
49
- }
50
- f2.link(:bye, :out, nil)
51
- }
52
- f.task(:out, Hop) { |t|
53
- t.link(nil, :done, nil)
54
- }
55
- f.task(:done, ::OFlow::Actors::Ignore)
56
- }
57
-
58
- # see if the flow was constructed correctly
59
- assert_equal(%|OFlow::Env {
60
- nest (OFlow::Flow) {
61
- log (Collector) {
62
- }
63
- trigger (Hop) {
64
- => deep:
65
- }
66
- deep (OFlow::Flow) {
67
- one (Hop) {
68
- => two:
69
- }
70
- two (Hop) {
71
- => flow:bye
72
- }
73
- * one:
74
- bye => out:
75
- }
76
- out (Hop) {
77
- => done:
78
- }
79
- done (OFlow::Actors::Ignore) {
80
- }
81
- }
82
- }|, ::OFlow::Env.describe())
83
-
84
- # run it and check the output
85
- trigger.receive(:go, ::OFlow::Box.new(7))
86
- ::OFlow::Env.flush()
87
- assert_equal([['go 7', ':nest:trigger'],
88
- [' 7', ':nest:deep:one'],
89
- [' 7', ':nest:deep:two'],
90
- [' 7', ':nest:out']
91
- ], collector.collection)
92
-
93
- ::OFlow::Env.clear()
94
- end
95
-
96
- def test_flow_nest_deep
97
- trigger = nil
98
- collector = nil
99
- ::OFlow::Env.flow(:nest_deep, :opt1 => 1) { |f|
100
- # use collector as the log
101
- f.task(:log, Collector) { |t|
102
- collector = t.actor
103
- }
104
-
105
- # starts off the process
106
- trigger = f.task(:trigger, Hop) { |t|
107
- t.link(nil, :deep, nil)
108
- }
109
- # a nested flow
110
- f.flow(:deep) { |f2|
111
- f2.route(nil, :deeper, nil)
112
- f2.flow(:deeper) { |f3|
113
- f3.route(nil, :one, nil)
114
- f3.task(:one, Hop) { |t|
115
- t.link(nil, :two, nil)
116
- }
117
- f3.task(:two, Hop) { |t|
118
- t.link(nil, :flow, :bye)
119
- }
120
- f3.link(:bye, :flow, :bye)
121
- }
122
- f2.link(:bye, :out, nil)
123
- }
124
- f.task(:out, Hop) { |t|
125
- t.link(nil, :done, nil)
126
- }
127
- f.task(:done, ::OFlow::Actors::Ignore)
128
- }
129
-
130
- # see if the flow was constructed correctly
131
- assert_equal(%|OFlow::Env {
132
- nest_deep (OFlow::Flow) {
133
- log (Collector) {
134
- }
135
- trigger (Hop) {
136
- => deep:
137
- }
138
- deep (OFlow::Flow) {
139
- deeper (OFlow::Flow) {
140
- one (Hop) {
141
- => two:
142
- }
143
- two (Hop) {
144
- => flow:bye
145
- }
146
- * one:
147
- bye => flow:bye
148
- }
149
- * deeper:
150
- bye => out:
151
- }
152
- out (Hop) {
153
- => done:
154
- }
155
- done (OFlow::Actors::Ignore) {
156
- }
157
- }
158
- }|, ::OFlow::Env.describe())
159
-
160
- # run it and check the output
161
- trigger.receive(:go, ::OFlow::Box.new(7))
162
- ::OFlow::Env.flush()
163
- assert_equal([['go 7', ':nest_deep:trigger'],
164
- [' 7', ':nest_deep:deep:deeper:one'],
165
- [' 7', ':nest_deep:deep:deeper:two'],
166
- [' 7', ':nest_deep:out']
167
- ], collector.collection)
168
-
169
- ::OFlow::Env.clear()
170
- end
171
-
172
- def test_flow_nest_label
173
- trigger = nil
174
- collector = nil
175
- ::OFlow::Env.flow(:nest) { |f|
176
- # use collector as the log
177
- f.task(:log, Collector) { |t|
178
- collector = t.actor
179
- }
180
-
181
- # starts off the process
182
- trigger = f.task(:trigger, Hop) { |t|
183
- t.link(:go, :deep, :first)
184
- }
185
- # a nested flow
186
- f.flow(:deep) { |f2|
187
- f2.route(:first, :one, :hip)
188
- f2.task(:one, Hop) { |t|
189
- t.link(:hip, :two, :hop)
190
- }
191
- f2.task(:two, Hop) { |t|
192
- t.link(:hop, :flow, :get_out)
193
- }
194
- f2.link(:get_out, :out, :finish)
195
- }
196
- f.task(:out, Hop) { |t|
197
- t.link(:finish, :done, nil)
198
- }
199
- f.task(:done, ::OFlow::Actors::Ignore)
200
- }
201
-
202
- # run it and check the output
203
- trigger.receive(:go, ::OFlow::Box.new(7))
204
- ::OFlow::Env.flush()
205
- assert_equal([['go 7', ':nest:trigger'],
206
- ['hip 7', ':nest:deep:one'],
207
- ['hop 7', ':nest:deep:two'],
208
- ['finish 7', ':nest:out']
209
- ], collector.collection)
210
-
211
- ::OFlow::Env.clear()
212
- end
213
-
214
-
215
- end # FlowNestTest