libis-workflow 2.0.beta.13 → 2.0.beta.14
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 +4 -4
- data/README.md +42 -44
- data/lib/libis/workflow/action.rb +24 -0
- data/lib/libis/workflow/base/logging.rb +76 -0
- data/lib/libis/workflow/base/run.rb +11 -7
- data/lib/libis/workflow/base/work_item.rb +30 -108
- data/lib/libis/workflow/base/workflow.rb +10 -11
- data/lib/libis/workflow/base.rb +1 -0
- data/lib/libis/workflow/status.rb +83 -0
- data/lib/libis/workflow/task.rb +133 -145
- data/lib/libis/workflow/task_group.rb +62 -0
- data/lib/libis/workflow/tasks/analyzer.rb +2 -4
- data/lib/libis/workflow/version.rb +1 -1
- data/lib/libis/workflow/work_item.rb +2 -10
- data/lib/libis/workflow/worker.rb +3 -3
- data/lib/libis/workflow.rb +4 -0
- data/spec/task_spec.rb +0 -1
- data/spec/workflow_spec.rb +42 -39
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cf536dca7ee73ba80bf51318292bf07e006d10a7
|
4
|
+
data.tar.gz: 3a5bfd9e58632e117a86de20ea949c469b2f1801
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ef7cf24225f7f0e56615afd279ab54bc33ee484aa0bec30956b1db90179da92c30e4f856c548488da99ce26534cc20b2c7a3ea9826453dc621f090a212f216f2
|
7
|
+
data.tar.gz: c01a212ea18e595a25c79c1e55d49d94e8df43f431e8b5f8f79e1756aa8513beb0fe56f985853e00604588d137c6010dadc939358ee05e68a90fdb478dcacae0
|
data/README.md
CHANGED
@@ -49,7 +49,7 @@ name has to be provided to the job configuration so that the job can instantiate
|
|
49
49
|
will be able to execute the tasks in proper order on all the WorkItems supplied/collected. Each task can be implemented
|
50
50
|
with code to run or simply contain a list of child tasks.
|
51
51
|
|
52
|
-
One
|
52
|
+
One task is predefined:
|
53
53
|
::Libis::Workflow::Tasks::Analyzer - analyzes the workflow run and summarizes the results. It is always included as the
|
54
54
|
last task by the workflow unless you supply a closing task called 'Analyzer' yourself.
|
55
55
|
|
@@ -103,15 +103,17 @@ is a Hash with:
|
|
103
103
|
|
104
104
|
The ::Libis::Workflow::Task base class allready defines the following parameters:
|
105
105
|
* quiet: Prevent generating log output. Default: false
|
106
|
-
* abort_on_error: Stop all tasks when an error occurs. Default: false
|
107
|
-
* always_run: Run this task, even if the item failed a previous task. Default: false
|
108
|
-
* subitems: Do not process the given item, but only the subitems. Default: false
|
109
106
|
* recursive: Run the task on all subitems recursively. Default: false
|
107
|
+
* retry_count: Number of times to retry the task. Default: 0
|
108
|
+
* retry_interval: Number of seconds to wait between retries. Default: 10
|
110
109
|
|
111
|
-
If 'class' is not present, the default '::Libis::Workflow::
|
112
|
-
|
113
|
-
|
114
|
-
the chapter on 'Tasks' below for more information on tasks.
|
110
|
+
If 'class' is not present, the default '::Libis::Workflow::TaskGroup' with the given name will be instantiated, which
|
111
|
+
performs each sub-task on the item. If the task is configured to be recursive, it will iterate over the child items and
|
112
|
+
perform each sub-task on each of the child items. If a 'class' value is given, an instance of that class will be created
|
113
|
+
and the task will be handed the work item to process on. See the chapter on 'Tasks' below for more information on tasks.
|
114
|
+
|
115
|
+
Note that a task with custom processing will not execute sub-tasks. If you configured a processing task with subtasks
|
116
|
+
an exception will be thrown when trying to execute the job.
|
115
117
|
|
116
118
|
##### Input variable definition
|
117
119
|
|
@@ -276,17 +278,17 @@ perform on each work item:
|
|
276
278
|
As seen above, the task should define a method called process_item that takes one argument. The argument will be a
|
277
279
|
reference to the work item that it needs to perform an action on. The task has several option to progress after
|
278
280
|
performing its actions:
|
279
|
-
* return. This is considered a normal and successful operation result.
|
280
|
-
|
281
|
-
set to 'done' for the given task.
|
281
|
+
* return. This is considered a normal and successful operation result. After a successful return the item's status will
|
282
|
+
be set to 'done' for the given task.
|
282
283
|
* raise a ::Libis::WorkflowError. Indicates that something went wrong during the processing of the item. The item's
|
283
|
-
|
284
|
-
|
284
|
+
status will be set to failed for the given task and the exception message will be printed in the error log. Processing
|
285
|
+
will continue with the next item. This action is recommended for temporary or recoverable errors. The parent item will
|
286
|
+
be flagged as 'failed' if any of the child items failed.
|
285
287
|
* raise a ::Libis::WorkflowAbort. A severe and fatal error has occured. Processing will abort immediately and the
|
286
|
-
|
287
|
-
|
288
|
+
failure status will be escalated to all items up the item hierarchy. Due to the escalating behaviour, no message is
|
289
|
+
printed in the error log automatically, so it is up to the task to an appropriate log the error itself.
|
288
290
|
* raise any other Exception. Should be avoided, but if it happens nevertheless, it will cause the item to fail for the
|
289
|
-
|
291
|
+
given task and the exception message to be logged in the error log. It will not attempt to process the other items.
|
290
292
|
|
291
293
|
### Controlling behavior with parameters
|
292
294
|
|
@@ -294,43 +296,32 @@ You have some options to control how the task will behave in special cases. Thes
|
|
294
296
|
the task, which can be set (and fixed with the 'frozen' option) on the task, but can be configured at run-time with the
|
295
297
|
help of workflow input parameters and run options.
|
296
298
|
|
297
|
-
#### Performing an action on the work item and all child items recursively
|
298
|
-
|
299
|
-
With the 'recursive' parameter set to true, your task's process_item method will be called for the work item and then
|
300
|
-
once for each child and each child's children recursively.
|
301
|
-
|
302
|
-
#### Performing an action only on the child items, skipping the work item itself
|
303
|
-
|
304
|
-
The parameter 'subitems' decides if the item handed over to the task will be processed or if it will process only it's
|
305
|
-
child items. This will only work once, not recursively, but by organizing tasks hierarchically with 'subitems' set to
|
306
|
-
true, it is possible to make sure that only items on a certain hierarchy level are performed. Recommended for workflows
|
307
|
-
where a well-known and fixed hierarchical structure has to be processed selectively.
|
308
|
-
|
309
|
-
Alternatively the 'recursive' option can be set and the 'process_item' method could check for certain item types,
|
310
|
-
properties or hierarchy levels to decide to perform the operation. This approach is more flexible but harder to
|
311
|
-
understand unless well documented.
|
312
|
-
|
313
299
|
#### Preventing any logging output from the task
|
314
300
|
|
315
301
|
Logging output can be blocked on a task-by-task basis by setting the 'quiet' parameter to true. Probably not usefull
|
316
302
|
except for the Analyzer task where the parameter is fixed to true. Logging output would otherwise intervene with the
|
317
303
|
log summary processing performed by the task.
|
318
304
|
|
319
|
-
####
|
320
|
-
|
321
|
-
When a task is so critical in the workflow process that any failure renders further processing useless, the parameter
|
322
|
-
'abort_on_error' can be turned on. Raising a ::Libis::WorkflowAbort exception would perform the same thing, but the
|
323
|
-
parameter makes the configuration more flexible.
|
305
|
+
#### Performing an action on the work item and all child items recursively
|
324
306
|
|
325
|
-
|
307
|
+
With the 'recursive' parameter set to true, your task's process_item method will be called for the work item and then
|
308
|
+
once for each child and each child's children recursively.
|
326
309
|
|
327
|
-
|
328
|
-
|
329
|
-
|
310
|
+
Note: you should not make both parent and child tasks recursive as this will cause the subitems to be processed
|
311
|
+
multiple times. If you make the parent task recursive, all tasks and sub-tasks will be performed on each item in the
|
312
|
+
tree. Making the child tasks recursive makes the parent task only perform on the top item and then performs each
|
313
|
+
sub-task one-by-one for the whole item tree. The last option is the most efficient.
|
314
|
+
|
315
|
+
Attention should be paid for the
|
316
|
+
|
317
|
+
#### Retrying if task failed
|
330
318
|
|
331
|
-
The
|
332
|
-
|
333
|
-
task
|
319
|
+
The parameters 'retry_count' and 'retry_interval' control the task's behaviour if a task has to wait for a result for an
|
320
|
+
asynchonous job. A task could be waiting for a result from the other job which will be indicated by a 'ASYNC_WAIT'
|
321
|
+
status. Alternatively the task may know that the job is halted and waiting for user interaction, indicated with the
|
322
|
+
'ASYNC_HALT' status. Only when the status is 'ASYNC_WAIT', the task will retry its process. By default the 'retry_count'
|
323
|
+
is 0, which causes the task not to retry. Before retrying the task will pause for the number of seconds given in the
|
324
|
+
parameter 'retry_interval', which is 30 by default.
|
334
325
|
|
335
326
|
### Pre- and postprocessing
|
336
327
|
|
@@ -338,6 +329,13 @@ The default implementation of 'process' is to call 'pre_process' and then call '
|
|
338
329
|
followed by calling 'post_process'. The methods 'pre_process' and 'post_process' are no-operation methods by default,
|
339
330
|
but can be overwritten if needed.
|
340
331
|
|
332
|
+
The 'pre_process' is intended to re-initialize the task before processing a new item. It can also be used to force the
|
333
|
+
task to skip processing the items altogether by calling the 'skip_processing_item' method or to prevent a recursive
|
334
|
+
task from traveling further down the item tree by calling the 'stop_processing_subitems' method. The temporary locks
|
335
|
+
behave as reset-on-read switches and are only active for the processing of the current item.
|
336
|
+
|
337
|
+
The 'post_process' method can be used to update any object after the item processing.
|
338
|
+
|
341
339
|
### Convenience functions
|
342
340
|
|
343
341
|
#### get_root_item()
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Libis
|
2
|
+
module Workflow
|
3
|
+
module Action
|
4
|
+
|
5
|
+
RUN = 0
|
6
|
+
CONTINUE = 1
|
7
|
+
RETRY = 2
|
8
|
+
ALWAYS_RUN = 3
|
9
|
+
FAILED = 4
|
10
|
+
|
11
|
+
def next_success_action(action)
|
12
|
+
case action
|
13
|
+
when :run, :continue, :retry, :always_run
|
14
|
+
:always_run
|
15
|
+
when :failed
|
16
|
+
:failed
|
17
|
+
else
|
18
|
+
:failed
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module Libis
|
2
|
+
module Workflow
|
3
|
+
module Base
|
4
|
+
module Logging
|
5
|
+
|
6
|
+
# Helper function for the Tasks to add a log entry to the log_history.
|
7
|
+
#
|
8
|
+
# The supplied message structure is expected to contain the following fields:
|
9
|
+
# - :severity : ::Logger::Severity value
|
10
|
+
# - :id : optional message id
|
11
|
+
# - :text : message text
|
12
|
+
# - :task : list of tasks names (task hierarchy) that submits the message
|
13
|
+
#
|
14
|
+
# @param [Hash] message
|
15
|
+
def add_log(message = {})
|
16
|
+
msg = message_struct(message)
|
17
|
+
add_log_entry(msg)
|
18
|
+
self.save
|
19
|
+
end
|
20
|
+
|
21
|
+
def <=(message = {})
|
22
|
+
self.add_log(message)
|
23
|
+
end
|
24
|
+
|
25
|
+
# Add a structured message to the log history. The message text can be submitted as an integer or text. If an
|
26
|
+
# integer is submitted, it will be used to look up the text in the MessageRegistry. The message text will be
|
27
|
+
# passed to the % operator with the args parameter. If that failes (e.g. because the format string is not correct)
|
28
|
+
# the args value is appended to the message.
|
29
|
+
#
|
30
|
+
# @param [Symbol] severity
|
31
|
+
# @param [Hash] msg should contain message text as :id or :text and the hierarchical name of the task as :task
|
32
|
+
# @param [Array] args string format values
|
33
|
+
def log_message(severity, msg, *args)
|
34
|
+
# Prepare info from msg struct for use with string substitution
|
35
|
+
message_id, message_text = if msg[:id]
|
36
|
+
[msg[:id], MessageRegistry.instance.get_message(msg[:id])]
|
37
|
+
elsif msg[:text]
|
38
|
+
[0, msg[:text]]
|
39
|
+
else
|
40
|
+
[0, '']
|
41
|
+
end
|
42
|
+
task = msg[:task] || '*UNKNOWN*'
|
43
|
+
message_text = (message_text % args rescue "#{message_text} - #{args}")
|
44
|
+
|
45
|
+
self.add_log severity: severity, id: message_id.to_i, text: message_text, task: task
|
46
|
+
name = ''
|
47
|
+
begin
|
48
|
+
name = self.to_s
|
49
|
+
name = self.name
|
50
|
+
name = self.namepath
|
51
|
+
rescue
|
52
|
+
# do nothing
|
53
|
+
end
|
54
|
+
Config.logger.add(severity, message_text, ('%s - %s ' % [task, name]))
|
55
|
+
end
|
56
|
+
|
57
|
+
protected
|
58
|
+
|
59
|
+
SEV_LABEL = %w(DEBUG INFO WARN ERROR FATAL ANY) unless const_defined? :SEV_LABEL
|
60
|
+
|
61
|
+
# create and return a proper message structure
|
62
|
+
# @param [Hash] opts
|
63
|
+
def message_struct(opts = {})
|
64
|
+
opts.reverse_merge!(severity: ::Logger::INFO, code: nil, text: '')
|
65
|
+
{
|
66
|
+
severity: SEV_LABEL[opts[:severity]],
|
67
|
+
task: opts[:task],
|
68
|
+
code: opts[:code],
|
69
|
+
message: opts[:text]
|
70
|
+
}.cleanup
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -23,7 +23,7 @@ module Libis
|
|
23
23
|
module Run
|
24
24
|
include ::Libis::Workflow::Base::WorkItem
|
25
25
|
|
26
|
-
attr_accessor :tasks
|
26
|
+
attr_accessor :tasks, :action
|
27
27
|
|
28
28
|
def work_dir
|
29
29
|
# noinspection RubyResolve
|
@@ -49,7 +49,16 @@ module Libis
|
|
49
49
|
end
|
50
50
|
|
51
51
|
# Execute the workflow.
|
52
|
-
|
52
|
+
#
|
53
|
+
# The action parameter defines how the execution of the tasks will behave:
|
54
|
+
# - With the default :run action each task will be executed regardsless how the task performed on the item
|
55
|
+
# previously.
|
56
|
+
# - When using the :retry action a task will not perform on an item if it was successful the last time. This
|
57
|
+
# allows you to retry a run when an temporary error (e.g. asynchronous wait or halt) occured.
|
58
|
+
#
|
59
|
+
# @param [Symbol] action the type of action to take during this run. :run or :retry
|
60
|
+
def run(action = :run)
|
61
|
+
self.action = action
|
53
62
|
|
54
63
|
self.start_date = Time.now
|
55
64
|
|
@@ -58,16 +67,11 @@ module Libis
|
|
58
67
|
self.tasks = workflow.tasks(self)
|
59
68
|
configure_tasks self.options
|
60
69
|
|
61
|
-
self.status = :STARTED
|
62
70
|
|
63
71
|
self.tasks.each do |task|
|
64
|
-
# note: do not return as we want to give any remaining task in the queue the oportunity to run
|
65
|
-
next if self.failed? and not task.parameter(:always_run)
|
66
72
|
task.run self
|
67
73
|
end
|
68
74
|
|
69
|
-
self.status = :DONE unless self.failed?
|
70
|
-
|
71
75
|
end
|
72
76
|
|
73
77
|
protected
|
@@ -4,6 +4,8 @@ require 'backports/rails/hash'
|
|
4
4
|
require 'libis/tools/extend/hash'
|
5
5
|
|
6
6
|
require 'libis/workflow/config'
|
7
|
+
require 'libis/workflow/status'
|
8
|
+
require_relative 'logging'
|
7
9
|
|
8
10
|
module Libis
|
9
11
|
module Workflow
|
@@ -66,12 +68,11 @@ module Libis
|
|
66
68
|
# self.status_log << { c_at: ::Time.now, tasklist: tasklist, text: message }.cleanup
|
67
69
|
# end
|
68
70
|
#
|
69
|
-
# def status_label(status_entry)
|
70
|
-
# "#{status_entry[:tasklist].last rescue nil}#{status_entry[:text] rescue nil}"
|
71
|
-
# end
|
72
71
|
#
|
73
72
|
module WorkItem
|
74
73
|
include Enumerable
|
74
|
+
include Libis::Workflow::Status
|
75
|
+
include Libis::Workflow::Base::Logging
|
75
76
|
|
76
77
|
# String representation of the identity of the work item.
|
77
78
|
#
|
@@ -97,7 +98,9 @@ module Libis
|
|
97
98
|
self.names.join('/');
|
98
99
|
end
|
99
100
|
|
100
|
-
# File name
|
101
|
+
# File name safe version of the to_s output.
|
102
|
+
#
|
103
|
+
# The output should be safe to use as a file name to store work item
|
101
104
|
# data. Typical use is when extra file items are created by a task and need to be stored on disk. The default
|
102
105
|
# implementation URL-encodes (%xx) all characters except alphanumeric, '.' and '-'.
|
103
106
|
#
|
@@ -106,51 +109,6 @@ module Libis
|
|
106
109
|
self.to_s.gsub(/[^\w.-]/) { |s| '%%%02x' % s.ord }
|
107
110
|
end
|
108
111
|
|
109
|
-
# Gets the current status of the object.
|
110
|
-
#
|
111
|
-
# @return [Symbol] status code
|
112
|
-
def status
|
113
|
-
s = self.status_log.last
|
114
|
-
label = status_label(s)
|
115
|
-
label.empty? ? :NOT_STARTED : label.to_sym
|
116
|
-
end
|
117
|
-
|
118
|
-
# Changes the status of the object. The status changed is logged in the status_log with the current timestamp.
|
119
|
-
#
|
120
|
-
# @param [Symbol] s
|
121
|
-
def status=(s, tasklist = nil)
|
122
|
-
s, tasklist = s if s.is_a? Array
|
123
|
-
s = s.to_sym
|
124
|
-
add_status_log(s, tasklist)
|
125
|
-
self.save
|
126
|
-
end
|
127
|
-
|
128
|
-
# Check ingest status of the object. The status is checked to see if it ends in 'Failed'.
|
129
|
-
#
|
130
|
-
# @return [Boolean] true if the object failed, false otherwise
|
131
|
-
def failed?
|
132
|
-
self.status.to_s =~ /Failed$/i ? true : false
|
133
|
-
end
|
134
|
-
|
135
|
-
# Helper function for the Tasks to add a log entry to the log_history.
|
136
|
-
#
|
137
|
-
# The supplied message structure is expected to contain the following fields:
|
138
|
-
# - :severity : ::Logger::Severity value
|
139
|
-
# - :id : optional message id
|
140
|
-
# - :text : message text
|
141
|
-
# - :task : list of tasks names (task hierarchy) that submits the message
|
142
|
-
#
|
143
|
-
# @param [Hash] message
|
144
|
-
def add_log(message = {})
|
145
|
-
msg = message_struct(message)
|
146
|
-
add_log_entry(msg)
|
147
|
-
self.save
|
148
|
-
end
|
149
|
-
|
150
|
-
def <=(message = {})
|
151
|
-
; self.add_log(message);
|
152
|
-
end
|
153
|
-
|
154
112
|
# Iterates over the work item clients and invokes code on each of them.
|
155
113
|
def each
|
156
114
|
self.items.each { |item| yield item }
|
@@ -160,7 +118,7 @@ module Libis
|
|
160
118
|
#
|
161
119
|
# @param [WorkItem] item to be added to the child list :items
|
162
120
|
def add_item(item)
|
163
|
-
return self unless item and item.is_a? WorkItem
|
121
|
+
return self unless item and item.is_a? Libis::Workflow::Base::WorkItem
|
164
122
|
self.items << item
|
165
123
|
item.parent = self
|
166
124
|
self.save!
|
@@ -168,7 +126,28 @@ module Libis
|
|
168
126
|
self
|
169
127
|
end
|
170
128
|
|
171
|
-
|
129
|
+
alias_method :<<, :add_item
|
130
|
+
|
131
|
+
# Return item's parent
|
132
|
+
# @return [Libis::Workflow::Base::WorkItem]
|
133
|
+
def get_parent
|
134
|
+
self.parent
|
135
|
+
end
|
136
|
+
|
137
|
+
# go up the hierarchy and return the topmost work item
|
138
|
+
#
|
139
|
+
# @return [Libis::Workflow::Base::WorkItem]
|
140
|
+
def get_root
|
141
|
+
self.get_parent && self.get_parent.is_a?(Libis::Workflow::Base::WorkItem) && self.get_parent.get_root || self
|
142
|
+
end
|
143
|
+
|
144
|
+
# Get the top
|
145
|
+
#
|
146
|
+
# @return [Libis::Workflow::Base::Run]
|
147
|
+
def get_run
|
148
|
+
return self if self.is_a?(Libis::Workflow::Base::Run)
|
149
|
+
self.get_parent && self.get_parent.get_run || nil
|
150
|
+
end
|
172
151
|
|
173
152
|
# Dummy method. It is a placeholder for DB backed implementations. Wherever appropriate WorkItem#save will be
|
174
153
|
# called to save the current item's state. If state needs to persisted, you should override this method or make
|
@@ -182,63 +161,6 @@ module Libis
|
|
182
161
|
def save!
|
183
162
|
end
|
184
163
|
|
185
|
-
# Add a structured message to the log history. The message text can be submitted as an integer or text. If an
|
186
|
-
# integer is submitted, it will be used to look up the text in the MessageRegistry. The message text will be
|
187
|
-
# passed to the % operator with the args parameter. If that failes (e.g. because the format string is not correct)
|
188
|
-
# the args value is appended to the message.
|
189
|
-
#
|
190
|
-
# @param [Symbol] severity
|
191
|
-
# @param [Hash] msg should contain message text as :id or :text and the hierarchical name of the task as :task
|
192
|
-
# @param [Array] args string format values
|
193
|
-
def log_message(severity, msg, *args)
|
194
|
-
# Prepare info from msg struct for use with string substitution
|
195
|
-
message_id, message_text = if msg[:id]
|
196
|
-
[msg[:id], MessageRegistry.instance.get_message(msg[:id])]
|
197
|
-
elsif msg[:text]
|
198
|
-
[0, msg[:text]]
|
199
|
-
else
|
200
|
-
[0, '']
|
201
|
-
end
|
202
|
-
task = msg[:task] || '*UNKNOWN*'
|
203
|
-
message_text = (message_text % args rescue "#{message_text} - #{args}")
|
204
|
-
|
205
|
-
self.add_log severity: severity, id: message_id.to_i, text: message_text, task: task
|
206
|
-
name = ''
|
207
|
-
begin
|
208
|
-
name = self.to_s
|
209
|
-
name = self.name
|
210
|
-
name = self.namepath
|
211
|
-
rescue
|
212
|
-
# do nothing
|
213
|
-
end
|
214
|
-
Config.logger.add(severity, message_text, ('%s - %s ' % [task, name]))
|
215
|
-
end
|
216
|
-
|
217
|
-
protected
|
218
|
-
|
219
|
-
SEV_LABEL = %w(DEBUG INFO WARN ERROR FATAL ANY) unless const_defined? :SEV_LABEL
|
220
|
-
|
221
|
-
# go up the hierarchy and return the topmost work item
|
222
|
-
#
|
223
|
-
# @return [WorkItem] the root work item
|
224
|
-
def root
|
225
|
-
root = self
|
226
|
-
root = root.parent while root.parent and root.parent.is_a? WorkItem
|
227
|
-
root
|
228
|
-
end
|
229
|
-
|
230
|
-
# create and return a proper message structure
|
231
|
-
# @param [Hash] opts
|
232
|
-
def message_struct(opts = {})
|
233
|
-
opts.reverse_merge!(severity: ::Logger::INFO, code: nil, text: '')
|
234
|
-
{
|
235
|
-
severity: SEV_LABEL[opts[:severity]],
|
236
|
-
task: opts[:task],
|
237
|
-
code: opts[:code],
|
238
|
-
message: opts[:text]
|
239
|
-
}.cleanup
|
240
|
-
end
|
241
|
-
|
242
164
|
end
|
243
165
|
|
244
166
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
3
|
require 'libis/tools/parameter'
|
4
|
+
require 'libis/workflow/task_group'
|
4
5
|
|
5
6
|
module Libis
|
6
7
|
module Workflow
|
@@ -31,17 +32,14 @@ module Libis
|
|
31
32
|
# A task definition is a Hash with the following values:
|
32
33
|
# - class: [String] the class name of the task including the module names
|
33
34
|
# - name: [String] optional if class is present. A friendly name for the task that will be used in the logs.
|
34
|
-
# - subitems: [Boolean] execute the task on the items in the current level or on the
|
35
|
-
# child items of the current level. This parameter can be used in combination with the subtasks to
|
36
|
-
# control what objects in the hierarchy the tasks are executed against.
|
37
|
-
# - recursive: [Boolean] execute the task for the current level items only or automatically recurse through
|
38
|
-
# the item's hierarchy and execute on all items below.
|
39
35
|
# - tasks: [Array] a list of subtask defintions for this task.
|
36
|
+
#
|
40
37
|
# Additionally the task definition Hash may specify values for any other parameter that the task knows of.
|
41
|
-
# All tasks have parameters 'quiet', '
|
42
|
-
# the documentation of the task class.
|
38
|
+
# All tasks have parameters 'quiet', 'recursive', 'retry_count' and 'retry_interval'. For more
|
39
|
+
# information about these see the documentation of the task class.
|
40
|
+
#
|
43
41
|
# A task definition does not require to have a 'class' entry. If not present the default
|
44
|
-
# ::Libis::Workflow::
|
42
|
+
# ::Libis::Workflow::TaskGroup class will be instatiated. It will do nothing itself, but will execute the
|
45
43
|
# subtasks on the item(s). In such case a 'name' is mandatory.
|
46
44
|
#
|
47
45
|
# These values should be set by calling the #configure method which takes a Hash as argument with :name,
|
@@ -75,6 +73,7 @@ module Libis
|
|
75
73
|
end
|
76
74
|
|
77
75
|
def self.included(base)
|
76
|
+
|
78
77
|
base.extend ClassMethods
|
79
78
|
end
|
80
79
|
|
@@ -138,13 +137,13 @@ module Libis
|
|
138
137
|
end
|
139
138
|
|
140
139
|
def instantize_task(parent, cfg)
|
141
|
-
task_class =
|
140
|
+
task_class = Libis::Workflow::TaskGroup
|
142
141
|
task_class = cfg[:class].constantize if cfg[:class]
|
143
142
|
# noinspection RubyArgCount
|
144
143
|
task_instance = task_class.new(parent, cfg)
|
145
|
-
cfg[:tasks].map do |task_cfg|
|
144
|
+
cfg[:tasks] && cfg[:tasks].map do |task_cfg|
|
146
145
|
task_instance << instantize_task(task_instance, task_cfg)
|
147
|
-
end
|
146
|
+
end
|
148
147
|
task_instance
|
149
148
|
end
|
150
149
|
|
data/lib/libis/workflow/base.rb
CHANGED
@@ -0,0 +1,83 @@
|
|
1
|
+
module Libis
|
2
|
+
module Workflow
|
3
|
+
module Status
|
4
|
+
|
5
|
+
STATUS = {
|
6
|
+
NOT_STARTED: 0,
|
7
|
+
STARTED: 1,
|
8
|
+
DONE: 2,
|
9
|
+
ASYNC_WAIT: 3,
|
10
|
+
ASYNC_HALT: 4,
|
11
|
+
FAILED: 5
|
12
|
+
}
|
13
|
+
|
14
|
+
# Changes the status of the object. The status changed is logged in the status_log with the current timestamp.
|
15
|
+
#
|
16
|
+
# @param [Array] x Array with status and task
|
17
|
+
def status=(x)
|
18
|
+
s, task = x
|
19
|
+
self.add_status_log(task: task, status: s)
|
20
|
+
self.save
|
21
|
+
end
|
22
|
+
|
23
|
+
# Get last known status symbol for a given task
|
24
|
+
#
|
25
|
+
# @param [String] task task name to check item status for
|
26
|
+
# @return [Symbol] the status code
|
27
|
+
def status(task = nil)
|
28
|
+
entry = status_entry(task)
|
29
|
+
status_symbol(entry[:status]) rescue :NOT_STARTED
|
30
|
+
end
|
31
|
+
|
32
|
+
# Gets the last known status label of the object.
|
33
|
+
#
|
34
|
+
# @param [String] task name of task to get the status for
|
35
|
+
# @return [String] status label ( = task name + status )
|
36
|
+
def status_label(task = nil)
|
37
|
+
entry = self.status_entry(task)
|
38
|
+
"#{entry[:task] rescue nil}#{entry[:status].capitalize rescue nil}"
|
39
|
+
end
|
40
|
+
|
41
|
+
# Check status of the object.
|
42
|
+
#
|
43
|
+
# @param [Symbol] state status to look for
|
44
|
+
# @param [String] task name of task whose status to check
|
45
|
+
# @return [Boolean] true if the object status matches
|
46
|
+
def check_status(state, task = nil)
|
47
|
+
self.status(task) == state
|
48
|
+
end
|
49
|
+
|
50
|
+
# Compare status with current status of the object.
|
51
|
+
#
|
52
|
+
# @param [Symbol] state
|
53
|
+
# @return [Integer] 1, 0 or -1 depnding on which
|
54
|
+
def compare_status(state, task = nil)
|
55
|
+
STATUS[self.status(task)] <=> STATUS[state]
|
56
|
+
end
|
57
|
+
|
58
|
+
protected
|
59
|
+
|
60
|
+
# Get last known status entry for a given task
|
61
|
+
#
|
62
|
+
# @param [String] task task name to check item status for
|
63
|
+
# @return [Hash] the status entry
|
64
|
+
def status_entry(task = nil)
|
65
|
+
return self.status_log.last if task.blank?
|
66
|
+
self.status_log.select { |entry| entry[:task] == task }.last
|
67
|
+
end
|
68
|
+
|
69
|
+
# Convert String, Symbol or Integer to correct symbol for the status.
|
70
|
+
# If the input value is nil, the fist status entry is returned.
|
71
|
+
#
|
72
|
+
# @param [String|Symbol|Integer] x string, symbol or integer for status code.
|
73
|
+
# @return [Symbol] the corresponding STATUS symbol
|
74
|
+
def status_symbol(x)
|
75
|
+
return STATUS.key(x) if x.is_a?(Integer)
|
76
|
+
return x if STATUS.has_key?(x)
|
77
|
+
x = x.to_s.upcase.to_sym
|
78
|
+
STATUS.has_key?(x) ? x : nil
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|