oflow 0.6.0 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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