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

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