libis-workflow 2.0.beta.9 → 2.0.beta.10

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 33d4917463c7c17ee5cd775275ccfe09c00a9360
4
- data.tar.gz: f22d17de924236c69fefad0958257209d6cd94e2
3
+ metadata.gz: 23bc91f367eb73cccde5236f1dde4720145a09a3
4
+ data.tar.gz: f5431781f4a3cd3cb2289c55531b96dd8244d187
5
5
  SHA512:
6
- metadata.gz: 85837ac165f1e2d720ff6ca7d4386576b653eb592ff2bf721708253ce9549bc97df7a0d90003427c1e670a9bf66992f8151279bdc86c002f1021e65bc6135842
7
- data.tar.gz: 59415cf0503c7821d3ee363760ba686114d1258bb142b5aa1cda68d03dcb8dab1a7076374fb9d1bc1bf75c99844424fe7f87543e03f0a4d2ebba4c2db34c260b
6
+ metadata.gz: e530a4ee73533d7ea9d3419d1c5473d770a9d6e9fa8e770d78bdf2266a9439ced5300baf7a2f7c269bd341057997a6190b5564e41a1c4610c0a88d6314aaf989
7
+ data.tar.gz: abbac4ae9505e6634b96d3af9aa7f93bd0644f2f901cecb0a216f19ac6a645536bbeae38a4bc55f24c0b171aa39e0df019ec30c59864bc5a1015d0bc6c52a01a
data/.travis.yml CHANGED
@@ -1,30 +1,25 @@
1
1
  language: ruby
2
- services: mongodb
2
+ sudo: false
3
3
  bundler_args: --without development
4
4
  cache: bundler
5
5
  rvm:
6
- - 1.9.3
7
- - 2.1
8
- - 2.2
6
+ - 2.1.0
7
+ - 2.2.0
9
8
  - ruby-head
10
- - jruby-19mode
9
+ - jruby-9.0.1.0
11
10
  jdk:
12
11
  - openjdk7
13
12
  - oraclejdk7
14
13
  - oraclejdk8
15
14
  matrix:
16
15
  exclude:
17
- - rvm: 1.9.3
16
+ - rvm: 2.1.0
18
17
  jdk: oraclejdk7
19
- - rvm: 1.9.3
18
+ - rvm: 2.1.0
20
19
  jdk: oraclejdk8
21
- - rvm: 2.1
20
+ - rvm: 2.2.0
22
21
  jdk: oraclejdk7
23
- - rvm: 2.1
24
- jdk: oraclejdk8
25
- - rvm: 2.2
26
- jdk: oraclejdk7
27
- - rvm: 2.2
22
+ - rvm: 2.2.0
28
23
  jdk: oraclejdk8
29
24
  - rvm: ruby-head
30
25
  jdk: oraclejdk7
data/README.md CHANGED
@@ -26,26 +26,35 @@ Or install it yourself as:
26
26
  ## Architecture
27
27
 
28
28
  This gem is essentially a simple, custom workflow system. The core of the workflow are the tasks. You can - and should -
29
- create your own tasks by creating new classes and include ::Libis::Workflow::Task. The ::Libis::Workflow::Task module
29
+ create your own tasks by creating new classes inherited from ::Libis::Workflow::Task. The ::Libis::Workflow::Task class
30
30
  and the included ::Libis::Workflow::Base::Logger module provide the necessary attributes and methods to make them work
31
- in the workflow. See the detailed documentation for the modules for more information.
32
-
33
- The objects that the tasks will be working on should include the ::Libis::Workflow::WorkItem module.
34
- When working with file objects the module ::Libis::Workflow::FileItem and/or ::Libis::Workflow::DirItem modules should
35
- be included for additional file-specific functionality.
36
- Work items can be organized in different types and a hierarchical structure.
37
-
38
- All the tasks will be organized into a ::Libis::Workflow::WorkflowDefinition which will be able to execute the tasks in
39
- proper order on all the WorkItems supplied/collected. Each task can be implemented with code to run or simply contain a
40
- list of child tasks.
41
-
42
- Two tasks are predefined:
43
- ::Libis::Workflow::Tasks::VirusChecker - runs a virus check on each WorkItem that is also a FileItem.
31
+ in the workflow. See the detailed documentation for the class and module for more information.
32
+
33
+ The objects that the tasks will be working on should include the ::Libis::Workflow::Base::WorkItem module.
34
+ When working with file objects the module ::Libis::Workflow::Base::FileItem and/or ::Libis::Workflow::Base::DirItem
35
+ modules should be included for additional file-specific functionality.
36
+ Work items can be organized in different types and a hierarchical structure. A simple implementation of work items with
37
+ in-memory storage is provided as classes ::Libis::Workflow::WorkItem, ::Libis::Workflow::FileItem and
38
+ ::Libis::Workflow::DirItem.
39
+
40
+ All the tasks will be organized into a workflow object for which a base module ::Libis::Workflow::Base::Workflow is
41
+ provided. It contains all the basic logic required for proper configuration and operation. Again a in-memory
42
+ implementation is provided in the class ::Libis::Workflow::Workflow for your convenience to be used as-is or to derive
43
+ your own from.
44
+
45
+ The workflow object will be able to execute the tasks in proper order on all the WorkItems supplied/collected. Each
46
+ task can be implemented with code to run or simply contain a list of child tasks. When a workflow is executed a special
47
+ run object is created that captures the configuration, logs and workitems generated while executing the tasks. Essential
48
+ logic is provided in the module ::Libis::Workflow::Base::Run with a simple in-memory implementation in
49
+ ::Libis::Workflow::Run. The run object's class name has to be provided to the workflow configuration so that the
50
+ workflow can instantiate the correct object.
51
+
52
+ One tasks is predefined:
44
53
  ::Libis::Workflow::Tasks::Analyzer - analyzes the workflow run and summarizes the results. It is always included as the
45
54
  last task by the workflow unless you supply a closing task called 'Analyzer' yourself.
46
55
 
47
56
  The whole ingester workflow is configured by a Singleton object ::Libis::Workflow::Config which contains settings for
48
- logging, paths where tasks and workitems can be found and the path to the virus scanner program.
57
+ logging and paths where tasks and workitems can be found.
49
58
 
50
59
  ## Usage
51
60
 
@@ -60,17 +69,20 @@ well. This is shown in the examples below.
60
69
 
61
70
  ### Workflows
62
71
 
63
- A ::Libis::Workflow::WorkflowDefinition instance contains the definition of a workflow. Once instantiated, it can be run
64
- by calling the 'run' method. This will create a ::Libis::Workflow::WorkflowRun instance, configure it and call the 'run'
65
- method on it. The Workflow constructor takes no arguments, but is should be configured by calling the 'set_config'
66
- method with the workflow configuration as an argument. The 'run' method takes an option Hash as argument.
72
+ An implementation of ::Libis::Workflow::Base::Workflow contains the definition of a workflow. Once instantiated, it can
73
+ be run by calling the 'run' method. This will create an intance of an implementation of ::Libis::Workflow::Base::Run,
74
+ configure it and call the 'run' method on it. The Workflow constructor takes no arguments, but is should be configured
75
+ by calling the 'configure' method with the workflow configuration as an argument. The 'run' method takes an option Hash
76
+ as argument.
67
77
 
68
78
  #### Workflow configuration
69
79
 
70
80
  A workflow configuration is a Hash with:
81
+ * name: String to identify the workflow
82
+ * description: String with detailed textual information
71
83
  * tasks: Array of task descriptions
72
- * start_object: String with class name of the starting object to be created. An istance of this class will be created
73
- for each run and serves as the root work item for that particular run.
84
+ * run_object: String with class name of the ::Libis::Workflow::Base::Run implementation to be created. An istance of
85
+ this class will be created for each run and serves as the root work item for that particular run.
74
86
  * input: Hash with input variable definitions
75
87
 
76
88
  ##### Task description
@@ -79,7 +91,15 @@ is a Hash with:
79
91
  * class: String with class name of the task
80
92
  * name: String with the name of the task
81
93
  * tasks: Array with task definitions of sub-tasks
82
- * options: Hash with additional task configuration options (see 'Tasks - Configuration' for more info)
94
+ * any task parameter values. Each task can define parameters that configure the task. It is using the
95
+ ::Libis::Tools::Parameter class for this.
96
+
97
+ The ::Libis::Workflow::Task base class allready defines the following parameters:
98
+ * quiet: Prevent generating log output. Default: false
99
+ * abort_on_error: Stop all tasks when an error occurs. Default: false
100
+ * always_run: Run this task, even if the item failed a previous task. Default: false
101
+ * subitems: Do not process the given item, but only the subitems. Default: false
102
+ * recursive: Run the task on all subitems recursively. Default: false
83
103
 
84
104
  If 'class' is not present, the default '::Libis::Workflow::Task' with the given name will be instantiated, which simply
85
105
  iterates over the child items of the given work item and performs each sub-task on each of the child items. If a 'class'
@@ -88,28 +108,17 @@ the chapter on 'Tasks' below for more information on tasks.
88
108
 
89
109
  ##### Input variable definition
90
110
 
91
- The key of the input Hash is the unique id of the variable. The value is a Hash with:
92
- * name: String with the name of the input variable
93
- This value is used for display only
94
- * description: String with descriptive text explaining the use/meaning of the variable
95
- * type: String with the type of the variable
96
- Currently only 'String', 'Time' and 'Boolean' are supported. If the value is not present, 'String' is asumed.
97
- * default: String with the default value
98
- If the default value contains the string %s, it will be replaced with the current time in the format yymmddHHMMSS when
99
- the workflow is started. For boolean values, 'true', 'yes', 't', 'y' and 1 are all interpreted as boolean true.
100
-
101
- All of these Hash keys are optional. Each input variable key and value will be added to the root work item's option Hash.
102
-
103
- #### Options
104
-
105
- The option Hash contains special run-time configuration parameters for the workflow:
106
- * action: String with the action that should be taken. Currently only 'start' is supported. In the future support for
107
- 'restart' and 'continue' will be added.
108
- * interactive: Boolean that indicates if the user should be queried to input values for variables that have no value set.
109
- This will pause the workflow run and is therefore not compatible with scheduling the workflow. For unattended runs the
110
- options should be set to false, causing the run to throw an exception if an input variable is missing a value.
111
-
112
- Remaining values are considered to be (default) values for the input variables.
111
+ The input variables define parameters for the workflow. When a workflow is run, it can give values for any of these
112
+ input variable and the workflow run will use the new values instead of the defaults.
113
+
114
+ The key of the input Hash is the unique name of the variable. The value is another Hash with the parameter definition.
115
+ See ::Libis::Tools::Parameter for the content of this Hash.
116
+
117
+ An additional property of the parameters is the 'propagate_to' property. It defines how the workflow run should push
118
+ the values set for the input parameters to the parameters on the tasks. These task parameters can be addressed by a
119
+ '<Task class or Task name>[#<parameter name>]' string. If necessary the task class or name may be specified as a full
120
+ path with '/' separators. The parameter name part is optional and considered to be the same as the input parameter name
121
+ if absent.
113
122
 
114
123
  #### Run-time configuration
115
124
 
@@ -125,7 +134,7 @@ Creating your own work items is highly recommended and is fairly easy:
125
134
 
126
135
  ```ruby
127
136
 
128
- require 'libis/workflow/workitems'
137
+ require 'libis/workflow'
129
138
 
130
139
  class MyWorkItem < ::Libis::Workflow::WorkItem
131
140
  attr_accesor :name
@@ -137,13 +146,81 @@ Creating your own work items is highly recommended and is fairly easy:
137
146
  end
138
147
  ```
139
148
 
140
- Work items that are file-based should also include the ::Libis::Workflow::FileItem module:
149
+ or if a custom storage implementation is desired, a number of data items and methods require implementation:
150
+
151
+ ```ruby
152
+
153
+ require 'libis/workflow'
154
+
155
+ class MyWorkItem < MyStorageItem
156
+ include ::Libis::Workflow::Base::WorkItem
157
+
158
+ stored_attribute :parent
159
+ stored_attribute :items
160
+ stored_attribute :options
161
+ stored_attribute :properties
162
+ stored_attribute :log_history
163
+ stored_attribute :status_log
164
+ stored_attribute :summary
165
+
166
+ def initialize
167
+ self.parent = nil
168
+ self.items = []
169
+ self.options = {}
170
+ self.properties = {}
171
+ self.log_history = []
172
+ self.status_log = []
173
+ self.summary = {}
174
+ end
175
+
176
+ protected
177
+
178
+ def add_log_entry(msg)
179
+ self.log_history << msg.merge(c_at: ::Time.now)
180
+ end
181
+
182
+ def add_status_log(message, tasklist = nil)
183
+ self.status_log << { timestamp: ::Time.now, tasklist: tasklist, text: message }.cleanup
184
+ end
185
+
186
+ def status_label(status_entry)
187
+ "#{status_entry[:tasklist].last rescue nil}#{status_entry[:text] rescue nil}"
188
+ end
189
+
190
+ end
191
+ ```
192
+
193
+ Work items that are file-based can derive from the ::Libis::Workflow::FileItem class:
141
194
 
142
195
  ```ruby
143
196
 
144
- require 'libis/workflow/workitems'
197
+ require 'libis/workflow'
198
+
199
+ class MyFileItem < ::Libis::Workflow::FileItem
145
200
 
146
- class MyFileItem < ::Libis::Workflow::WorkItem
201
+ def initialize(file)
202
+ filename = file
203
+ super
204
+ end
205
+
206
+ def filesize
207
+ properties[:size]
208
+ end
209
+
210
+ def fixity_check(checksum)
211
+ properties[:checksum] == checksum
212
+ end
213
+
214
+ end
215
+ ```
216
+
217
+ or include the ::Libis::Workflow::Base::FileItem module:
218
+
219
+ ```ruby
220
+
221
+ require 'libis/workflow'
222
+
223
+ class MyFileItem < MyWorkItem
147
224
  include ::Libis::Workflow::FileItem
148
225
 
149
226
  def initialize(file)
@@ -162,6 +239,8 @@ Work items that are file-based should also include the ::Libis::Workflow::FileIt
162
239
  end
163
240
  ```
164
241
 
242
+
243
+
165
244
  ## Tasks
166
245
 
167
246
  Tasks should inherit from ::Libis::Workflow::Task and specify the actions it wants to
@@ -172,69 +251,85 @@ perform on each work item:
172
251
  class MyTask < ::Libis::Workflow::Task
173
252
 
174
253
  def process_item(item)
175
- item.perform_my_action
254
+ if do_something(item)
255
+ info "Did something"
256
+ else
257
+ raise ::Libis::WorkflowError, "Something went wrong"
258
+ end
176
259
  rescue Exception => e
177
- item.set_status(to_status(:failed))
260
+ error "Fatal problem, aborting"
261
+ raise ::Libis::WorkflowAbort, "Fatal problem"
262
+ ensure
263
+ item
178
264
  end
179
265
 
180
266
  end
181
267
  ```
182
268
 
183
- You have some options to specify the actions:
184
-
185
- ### Performing an action on each child item of the provided work item
186
-
187
- In that case the task should provide a 'process_item' method as above. Each child item will be passed as the argument
188
- to the method and perform whatever needs to be done on the item.
189
-
190
- If the action fails the method is expected to set the item status field to failed. This is also shown in the previous
191
- example. If the error is so severe that no other child items should be processed, the action can decide to throw an
192
- exception, preferably a ::Libis::Workflow::Exception or a child exception thereof.
269
+ As seen above, the task should define a method called process_item that takes one argument. The argument will be a
270
+ reference to the work item that it needs to perform an action on. The task has several option to progress after
271
+ performing its actions:
272
+ * return. This is considered a normal and successful operation result. If the item was replaced by a new item or if the
273
+ item tree has changed, it is recommended to return the new item. After a successful return the item's status will be
274
+ set to 'done' for the given task.
275
+ * raise a ::Libis::WorkflowError. Indicates that something went wrong during the processing of the item. The item's
276
+ status will be set to failed for the given task and the exception message will be printed in the error log. Processing
277
+ will continue with the next item. This action is recommended for temporary or recoverable errors.
278
+ * raise a ::Libis::WorkflowAbort. A severe and fatal error has occured. Processing will abort immediately and the
279
+ failure status will be escalated to all items up the item hierarchy. Due to the escalating behaviour, no message is
280
+ printed in the error log automatically, so it is up to the task to an appropriate log the error itself.
281
+ * raise any other Exception. Should be avoided, but if it happens nevertheless, it will cause the item to fail for the
282
+ given task and the exception message to be logged in the error log. It will attempt to process the other items.
283
+
284
+ ### Controlling behavior with parameters
285
+
286
+ You have some options to control how the task will behave in special cases. These are controlled using parameters on
287
+ the task, which can be set (and fixed with the 'frozen' option) on the task, but can be configured at run-time with the
288
+ help of workflow input parameters and run options.
289
+
290
+ #### Performing an action on the work item and all child items recursively
291
+
292
+ With the 'recursive' parameter set to true, your task's process_item method will be called for the work item and then
293
+ once for each child and each child's children recursively.
193
294
 
194
- ### Performing an action on the provided work item
295
+ #### Performing an action only on the child items, skipping the work item itself
195
296
 
196
- If the task wants to perform an action on the work item directly, it should define a 'process' method. The work item is
197
- available to the method as class instance variable 'workitem'. Again the method is responsible to communicate errors
198
- with a failed status or by throwing an exception.
297
+ The parameter 'subitems' decides if the item handed over to the task will be processed or if it will process only it's
298
+ child items. This will only work once, not recursively, but by organizing tasks hierarchically with 'subitems' set to
299
+ true, it is possible to make sure that only items on a certain hierarchy level are performed. Recommended for workflows
300
+ where a well-known and fixed hierarchical structure has to be processed selectively.
199
301
 
200
- ### Combining both
302
+ Alternatively the 'recursive' option can be set and the 'process_item' method could check for certain item types,
303
+ properties or hierarchy levels to decide to perform the operation. This approach is more flexible but harder to
304
+ understand unless well documented.
201
305
 
202
- It is possible to perform some action on the parent work item first and then process each child item. Processing the
203
- child items should be done in process_item as usual, but processing the parent item can be done either by defining a
204
- pre_process method or a process method that ends with a 'super' call. Using this should be an exception as it is
205
- recommended to create a seperate task to process the child work items.
306
+ #### Preventing any logging output from the task
206
307
 
207
- ### Default behaviour
308
+ Logging output can be blocked on a task-by-task basis by setting the 'quiet' parameter to true. Probably not usefull
309
+ except for the Analyzer task where the parameter is fixed to true. Logging output would otherwise intervene with the
310
+ log summary processing performed by the task.
208
311
 
209
- The default implementation of 'process' is to call 'pre_process' and then call 'process_item' on each child item.
210
-
211
- The default implementation for 'process_item' is to run each child task for each given child item. This will raise an
212
- exception unless the workflow has defined some sub-tasks for this task. This means that in the workflow definition tree
213
- each leaf task should either implement it's own 'process_item' method or override the 'process' method. Only non-leaf
214
- nodes in the workflow definition tree are allowed to use the default implementation (by defining only 'name' and 'tasks'
215
- value). See above on 'Workflow configuration' for more info.
312
+ #### Aborting the task whenever any item fails
313
+
314
+ When a task is so critical in the workflow process that any failure renders further processing useless, the parameter
315
+ 'abort_on_error' can be turned on. Raising a ::Libis::WorkflowAbort exception would perform the same thing, but the
316
+ parameter makes the configuration more flexible.
216
317
 
217
- ### Configuration
318
+ #### Always running a task, even on items that failed in an earlier stage in the workflow
218
319
 
219
- The task takes some options that determine how the task will be handling special cases. The options should be passed to
220
- the Task constructor as part of the initialization. The workflow configuration will take care of that.
320
+ The opposite of aborting on error, the parameter 'always_run' can be set to true to force a task to process the items
321
+ even if the item has a failed status from a previous task. Note that this will cause the item's status to no longer be
322
+ failing until a task fails on the item again. The old failed status will be tracable in the status history.
221
323
 
222
- * quiet: Boolean - default: false
223
- * always_run: Boolean - default: false
224
- * items_first: Boolean - default: false
324
+ The parameter only configures the task on which it is set. If the task is a subtask it will only be forced to run if
325
+ any of it's previous sibling tasks failed. In order to force the run, even if the item failed in another branch of the
326
+ task hiearchy, the parent tasks should have their 'always_run' parameter also set to true.
225
327
 
226
- The quiet option surpresses all logging for this task.
328
+ ### Pre- and postprocessing
227
329
 
228
- When the option always_run is set, the task will run even when a previous task failed to run on the item before. Note
229
- that successfully running such a task will unmark the item as failed. The status history of the item will show which
230
- tasks failed. Only use this option if you are sure the task will fully recover if the previous tasks failed or did not
231
- run due to a previous failure.
232
-
233
- The items_fist option determines the processing order. If a task has multiple subtasks and the given workitem has
234
- multiple subitems, setting the items_first option will cause it to take the first subitem, run the first subtask on it,
235
- then the second subtask and so on. Next it will run the first, second, ... subtask on the second subitem and so on. If
236
- the option is not set or set to false, the first subtask will run on each subitem, then the second subtask on each
237
- subitem, and so on.
330
+ The default implementation of 'process' is to call 'pre_process' and then call 'process_item' on each child item,
331
+ followed by calling 'post_process'. The methods 'pre_process' and 'post_process' are no-operation methods by default,
332
+ but can be overwritten if needed.
238
333
 
239
334
  ### Convenience functions
240
335
 
@@ -260,6 +355,7 @@ stderr string.
260
355
  #### names()
261
356
 
262
357
  An array of strings with the hierarchical path of tasks leading to the current task. Can be usefull for log messages.
358
+ The method 'namepath' returns a '/' separated path of tasks.
263
359
 
264
360
  #### (debug/info/warn/error/fatal)(message, *args)
265
361
 
@@ -0,0 +1,15 @@
1
+ # encoding: utf-8
2
+
3
+ require 'libis/workflow/base/file_item'
4
+
5
+ module Libis
6
+ module Workflow
7
+ module Base
8
+
9
+ module DirItem
10
+ include ::Libis::Workflow::Base::FileItem
11
+ end
12
+
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,82 @@
1
+ # encoding: utf-8
2
+
3
+ require 'digest'
4
+
5
+ require 'libis/workflow/base/work_item'
6
+
7
+ module Libis
8
+ module Workflow
9
+ module Base
10
+
11
+ # noinspection RubyResolve
12
+ module FileItem
13
+ include Libis::Workflow::Base::WorkItem
14
+
15
+ def filename
16
+ File.basename(self.properties[:filename]) || self.properties[:link]
17
+ end
18
+
19
+ def name
20
+ self.properties[:name] || self.filename
21
+ end
22
+
23
+ def filelist
24
+ (self.parent.filelist rescue Array.new).push(filename).compact
25
+ end
26
+
27
+ def filepath
28
+ self.filelist.join('/')
29
+ end
30
+
31
+ def fullpath
32
+ self.properties[:filename]
33
+ end
34
+
35
+ def filename=(name)
36
+ begin
37
+ stats = ::File.stat name
38
+ self.properties[:size] = stats.size
39
+ self.properties[:access_time] = stats.atime
40
+ self.properties[:modification_time] = stats.mtime
41
+ self.properties[:creation_time] = stats.ctime
42
+ self.properties[:mode] = stats.mode
43
+ self.properties[:uid] = stats.uid
44
+ self.properties[:gid] = stats.gid
45
+ set_checksum(:MD5, ::Digest::MD5.hexdigest(File.read(name))) if File.file?(name)
46
+ rescue
47
+ # ignored
48
+ end
49
+ self.properties[:filename] = name
50
+ end
51
+
52
+ def checksum(checksum_type)
53
+ self.properties[('checksum_' + checksum_type.to_s.downcase).to_sym]
54
+ end
55
+
56
+ def set_checksum(checksum_type, value)
57
+ self.properties[('checksum_' + checksum_type.to_s.downcase).to_sym] = value
58
+ end
59
+
60
+ def link
61
+ self.properties[:link]
62
+ end
63
+
64
+ def link=(name)
65
+ self.properties[:link] = name
66
+ end
67
+
68
+ def set_info(info)
69
+ info.each do |k, v|
70
+ self.properties[k] = v
71
+ end
72
+ end
73
+
74
+ def safe_name
75
+ self.name.to_s.gsub(/[^\w.-]/) { |s| '%%%02x' % s.ord }
76
+ end
77
+
78
+ end
79
+
80
+ end
81
+ end
82
+ end
@@ -2,23 +2,31 @@
2
2
 
3
3
  require 'fileutils'
4
4
 
5
- require 'libis/workflow/workitems/work_item'
5
+ require 'libis/workflow/base/work_item'
6
6
 
7
7
  module Libis
8
8
  module Workflow
9
9
  module Base
10
- module Run
11
- include ::Libis::Workflow::WorkItem
12
-
13
- def start_date; raise RuntimeError.new "Method not implemented: #{caller[0]}"; end
14
- def start_date=(_); raise RuntimeError.new "Method not implemented: #{caller[0]}"; end
15
10
 
16
- def tasks; raise RuntimeError.new "Method not implemented: #{caller[0]}"; end
17
- def tasks=(_); raise RuntimeError.new "Method not implemented: #{caller[0]}"; end
11
+ # Base module for all workflow runs. It is created by an associated workflow when the workflow is executed.
12
+ #
13
+ # This module lacks the implementation for the data attributes. It functions as an interface that describes the
14
+ # common functionality regardless of the storage implementation. These attributes require some implementation:
15
+ #
16
+ # - start_date: [Time] the timestamp of the execution of the run
17
+ # - workflow: [Object] a reference to the Workflow this Run belongs to
18
+ #
19
+ # Note that ::Libis::Workflow::Base::WorkItem is a parent module and therefore requires implementation of the
20
+ # attributes of that module too.
21
+ #
22
+ # A simple in-memory implementation can be found in ::Libis::Workflow::Run
23
+ module Run
24
+ include ::Libis::Workflow::Base::WorkItem
18
25
 
19
- def workflow; raise RuntimeError.new "Method not implemented: #{caller[0]}"; end
26
+ attr_accessor :tasks
20
27
 
21
28
  def work_dir
29
+ # noinspection RubyResolve
22
30
  dir = File.join(Config.workdir, self.name)
23
31
  FileUtils.mkpath dir unless Dir.exist?(dir)
24
32
  dir
@@ -36,6 +44,9 @@ module Libis
36
44
  self.name
37
45
  end
38
46
 
47
+ # Execute the workflow.
48
+ # @param [Hash] opts a list with parameter name and value tuples that specify the values for the workflow input
49
+ # parameters.
39
50
  def run(opts = {})
40
51
 
41
52
  self.start_date = Time.now
@@ -48,6 +59,7 @@ module Libis
48
59
  self.status = :STARTED
49
60
 
50
61
  self.tasks.each do |task|
62
+ # note: do not return as we want to give any remaining task in the queue the oportunity to run
51
63
  next if self.failed? and not task.parameter(:always_run)
52
64
  task.run self
53
65
  end