libis-workflow 2.0.beta.19-java
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.coveralls.yml +2 -0
- data/.gitignore +36 -0
- data/.travis.yml +32 -0
- data/Gemfile +4 -0
- data/LICENSE +21 -0
- data/README.md +397 -0
- data/Rakefile +7 -0
- data/lib/libis/exceptions.rb +8 -0
- data/lib/libis/workflow/action.rb +24 -0
- data/lib/libis/workflow/base/dir_item.rb +15 -0
- data/lib/libis/workflow/base/file_item.rb +82 -0
- data/lib/libis/workflow/base/job.rb +85 -0
- data/lib/libis/workflow/base/logger.rb +30 -0
- data/lib/libis/workflow/base/logging.rb +76 -0
- data/lib/libis/workflow/base/run.rb +86 -0
- data/lib/libis/workflow/base/work_item.rb +176 -0
- data/lib/libis/workflow/base/workflow.rb +153 -0
- data/lib/libis/workflow/base.rb +7 -0
- data/lib/libis/workflow/config.rb +24 -0
- data/lib/libis/workflow/dir_item.rb +12 -0
- data/lib/libis/workflow/file_item.rb +17 -0
- data/lib/libis/workflow/job.rb +26 -0
- data/lib/libis/workflow/message_registry.rb +32 -0
- data/lib/libis/workflow/run.rb +26 -0
- data/lib/libis/workflow/status.rb +83 -0
- data/lib/libis/workflow/task.rb +287 -0
- data/lib/libis/workflow/task_group.rb +62 -0
- data/lib/libis/workflow/tasks/analyzer.rb +49 -0
- data/lib/libis/workflow/version.rb +7 -0
- data/lib/libis/workflow/work_item.rb +43 -0
- data/lib/libis/workflow/worker.rb +42 -0
- data/lib/libis/workflow/workflow.rb +22 -0
- data/lib/libis/workflow.rb +40 -0
- data/lib/libis-workflow.rb +2 -0
- data/libis-workflow.gemspec +38 -0
- data/spec/items/test_dir_item.rb +15 -0
- data/spec/items/test_file_item.rb +18 -0
- data/spec/items/test_run.rb +10 -0
- data/spec/items.rb +3 -0
- data/spec/spec_helper.rb +8 -0
- data/spec/task_spec.rb +16 -0
- data/spec/tasks/camelize_name.rb +13 -0
- data/spec/tasks/checksum_tester.rb +33 -0
- data/spec/tasks/collect_files.rb +48 -0
- data/spec/workflow_spec.rb +188 -0
- metadata +196 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: c33864ac6963e1e65b061ec72575a3a78c5297ec
|
4
|
+
data.tar.gz: dd8d3ad399c31eb235b87df55d58e7dee65a6062
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: fbd0c33ede85632502787118d8398febec7f56828270d40409c396fbc3689ab8204f9f7fde4784cd3912cf4c0278f706845f1baf241651a03b2929155707f41e
|
7
|
+
data.tar.gz: 1028ba91dde40522ac90cf2696c6ba19950d0659cc7bf5636db297eeb078a91d003611bf7661ac08a482ecd31ed59ae518e071a6ccf90338242eadb52b4b0dca
|
data/.coveralls.yml
ADDED
data/.gitignore
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
/.config
|
4
|
+
/coverage/
|
5
|
+
/InstalledFiles
|
6
|
+
/pkg/
|
7
|
+
/spec/reports/
|
8
|
+
/test/tmp/
|
9
|
+
/test/version_tmp/
|
10
|
+
/tmp/
|
11
|
+
|
12
|
+
## Specific to RubyMotion:
|
13
|
+
.dat*
|
14
|
+
.repl_history
|
15
|
+
build/
|
16
|
+
|
17
|
+
## Documentation cache and generated files:
|
18
|
+
/.yardoc/
|
19
|
+
/_yardoc/
|
20
|
+
/doc/
|
21
|
+
/rdoc/
|
22
|
+
|
23
|
+
## Environment normalisation:
|
24
|
+
/.bundle/
|
25
|
+
/lib/bundler/man/
|
26
|
+
|
27
|
+
# for a library or gem, you might want to ignore these files since the code is
|
28
|
+
# intended to run in multiple environments; otherwise, check them in:
|
29
|
+
Gemfile.lock
|
30
|
+
.ruby-version
|
31
|
+
.ruby-gemset
|
32
|
+
|
33
|
+
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
34
|
+
.rvmrc
|
35
|
+
|
36
|
+
.idea/
|
data/.travis.yml
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
language: ruby
|
2
|
+
sudo: false
|
3
|
+
bundler_args: --without development
|
4
|
+
cache: bundler
|
5
|
+
rvm:
|
6
|
+
- 2.1.0
|
7
|
+
- 2.2.0
|
8
|
+
- ruby-head
|
9
|
+
- jruby-9.0.1.0
|
10
|
+
jdk:
|
11
|
+
- openjdk7
|
12
|
+
- oraclejdk7
|
13
|
+
- oraclejdk8
|
14
|
+
matrix:
|
15
|
+
exclude:
|
16
|
+
- rvm: 2.1.0
|
17
|
+
jdk: oraclejdk7
|
18
|
+
- rvm: 2.1.0
|
19
|
+
jdk: oraclejdk8
|
20
|
+
- rvm: 2.2.0
|
21
|
+
jdk: oraclejdk7
|
22
|
+
- rvm: 2.2.0
|
23
|
+
jdk: oraclejdk8
|
24
|
+
- rvm: ruby-head
|
25
|
+
jdk: oraclejdk7
|
26
|
+
- rvm: ruby-head
|
27
|
+
jdk: oraclejdk8
|
28
|
+
allow_failures:
|
29
|
+
- rvm: ruby-head
|
30
|
+
branches:
|
31
|
+
only:
|
32
|
+
- master
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2014 LIBIS
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,397 @@
|
|
1
|
+
|
2
|
+
[![Build Status](https://travis-ci.org/Kris-LIBIS/workflow.svg?branch=master)](https://travis-ci.org/Kris-LIBIS/workflow)
|
3
|
+
[![Coverage Status](https://img.shields.io/coveralls/Kris-LIBIS/workflow.svg)](https://coveralls.io/r/Kris-LIBIS/workflow)
|
4
|
+
|
5
|
+
# LIBIS Workflow
|
6
|
+
|
7
|
+
LIBIS Workflow framework
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
Add this line to your application's Gemfile:
|
12
|
+
|
13
|
+
```ruby
|
14
|
+
gem 'libis-workflow'
|
15
|
+
```
|
16
|
+
|
17
|
+
|
18
|
+
And then execute:
|
19
|
+
|
20
|
+
$ bundle
|
21
|
+
|
22
|
+
Or install it yourself as:
|
23
|
+
|
24
|
+
$ gem install 'libis-workflow'
|
25
|
+
|
26
|
+
## Architecture
|
27
|
+
|
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 inherited from ::Libis::Workflow::Task. The ::Libis::Workflow::Task class
|
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 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 Job class is responsible for instantiating a run-time workflow execution object - a Run - that captures the
|
46
|
+
configuration, logs and workitems generated while executing the tasks. Essential logic is provided in the module
|
47
|
+
::Libis::Workflow::Base::Run with a simple in-memory implementation in ::Libis::Workflow::Run. The run object's class
|
48
|
+
name has to be provided to the job configuration so that the job can instantiate the correct object. The run object
|
49
|
+
will be able to execute the tasks in proper order on all the WorkItems supplied/collected. Each task can be implemented
|
50
|
+
with code to run or simply contain a list of child tasks.
|
51
|
+
|
52
|
+
One task is predefined:
|
53
|
+
::Libis::Workflow::Tasks::Analyzer - analyzes the workflow run and summarizes the results. It is always included as the
|
54
|
+
last task by the workflow unless you supply a closing task called 'Analyzer' yourself.
|
55
|
+
|
56
|
+
The whole ingester workflow is configured by a Singleton object ::Libis::Workflow::Config which contains settings for
|
57
|
+
logging and paths where tasks and workitems can be found.
|
58
|
+
|
59
|
+
## Usage
|
60
|
+
|
61
|
+
You should start by including the following line in your source code:
|
62
|
+
|
63
|
+
```ruby
|
64
|
+
require 'libis-workflow'
|
65
|
+
```
|
66
|
+
|
67
|
+
This will load all of the Libis Workflow framework into your environment, but including only the required parts is OK as
|
68
|
+
well. This is shown in the examples below.
|
69
|
+
|
70
|
+
### Workflows and Jobs
|
71
|
+
|
72
|
+
An implementation of ::Libis::Workflow::Base::Workflow contains the definition of a workflow. Once instantiated, it can
|
73
|
+
be run by calling the 'execute' method on a job object created for that workflow. This will create an intance of an
|
74
|
+
implementation of ::Libis::Workflow::Base::Run, configure it and call the 'run' method on it. The Workflow constructor
|
75
|
+
takes no arguments, but is should be configured by calling the 'configure' method with the workflow configuration as an
|
76
|
+
argument. The job's 'execute' method takes an option Hash as argument with extra/overriding configuration values.
|
77
|
+
|
78
|
+
### Job configuration
|
79
|
+
A job configuration is a Hash with:
|
80
|
+
* name: String to identify the workflow
|
81
|
+
* description: String with detailed textual information
|
82
|
+
* workflow: Object reference to a Workflow that contains the task configuration
|
83
|
+
* run_object: String with class name of the ::Libis::Workflow::Base::Run implementation to be created. An istance of
|
84
|
+
this class will be created for each run and serves as the root work item for that particular run.
|
85
|
+
* input: Hash with input parameter values for the workflow
|
86
|
+
|
87
|
+
#### Workflow configuration
|
88
|
+
|
89
|
+
A workflow configuration is a Hash with:
|
90
|
+
* name: String to identify the workflow
|
91
|
+
* description: String with detailed textual information
|
92
|
+
* tasks: Array of task descriptions
|
93
|
+
* input: Hash with input variable definitions
|
94
|
+
|
95
|
+
##### Task description
|
96
|
+
|
97
|
+
is a Hash with:
|
98
|
+
* class: String with class name of the task
|
99
|
+
* name: String with the name of the task
|
100
|
+
* tasks: Array with task definitions of sub-tasks
|
101
|
+
* any task parameter values. Each task can define parameters that configure the task. It is using the
|
102
|
+
::Libis::Tools::Parameter class for this.
|
103
|
+
|
104
|
+
The ::Libis::Workflow::Task base class allready defines the following parameters:
|
105
|
+
* quiet: Prevent generating log output. Default: false
|
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
|
109
|
+
|
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.
|
117
|
+
|
118
|
+
##### Input variable definition
|
119
|
+
|
120
|
+
The input variables define parameters for the workflow. When a job is executed, it can provide values for any of these
|
121
|
+
input variables and the workflow run will use the new values instead of the defaults.
|
122
|
+
|
123
|
+
The key of the input Hash is the unique name of the variable. The value is another Hash with the parameter definition.
|
124
|
+
See ::Libis::Tools::Parameter for the content of this Hash.
|
125
|
+
|
126
|
+
An additional property of the parameters is the 'propagate_to' property. It defines how the workflow run should push
|
127
|
+
the values set for the input parameters to the parameters on the tasks. These task parameters can be addressed by a
|
128
|
+
'<Task class or Task name>[#<parameter name>]' string. If necessary the task class or name may be specified as a full
|
129
|
+
path with '/' separators. The parameter name part is optional and considered to be the same as the input parameter name
|
130
|
+
if absent.
|
131
|
+
|
132
|
+
#### Run-time configuration
|
133
|
+
|
134
|
+
The job's 'execute' method takes an optional Hash as argument which will complement and override the options Hash
|
135
|
+
described in the previous chapter.
|
136
|
+
|
137
|
+
Once the workflow is configured and the root work item instantiated, the method will run each top-level task on the root
|
138
|
+
work item in sequence until all tasks have completed successfully or a task has failed.
|
139
|
+
|
140
|
+
### Work items
|
141
|
+
|
142
|
+
Creating your own work items is highly recommended and is fairly easy:
|
143
|
+
|
144
|
+
```ruby
|
145
|
+
|
146
|
+
require 'libis/workflow'
|
147
|
+
|
148
|
+
class MyWorkItem < ::Libis::Workflow::WorkItem
|
149
|
+
attr_accesor :name
|
150
|
+
|
151
|
+
def initialize
|
152
|
+
@name = 'My work item'
|
153
|
+
super # Note: this is important as the base class requires some initialization
|
154
|
+
end
|
155
|
+
end
|
156
|
+
```
|
157
|
+
|
158
|
+
or if a custom storage implementation is desired, a number of data items and methods require implementation:
|
159
|
+
|
160
|
+
```ruby
|
161
|
+
|
162
|
+
require 'libis/workflow'
|
163
|
+
|
164
|
+
class MyWorkItem < MyStorageItem
|
165
|
+
include ::Libis::Workflow::Base::WorkItem
|
166
|
+
|
167
|
+
stored_attribute :parent
|
168
|
+
stored_attribute :items
|
169
|
+
stored_attribute :options
|
170
|
+
stored_attribute :properties
|
171
|
+
stored_attribute :log_history
|
172
|
+
stored_attribute :status_log
|
173
|
+
stored_attribute :summary
|
174
|
+
|
175
|
+
def initialize
|
176
|
+
self.parent = nil
|
177
|
+
self.items = []
|
178
|
+
self.options = {}
|
179
|
+
self.properties = {}
|
180
|
+
self.log_history = []
|
181
|
+
self.status_log = []
|
182
|
+
self.summary = {}
|
183
|
+
end
|
184
|
+
|
185
|
+
protected
|
186
|
+
|
187
|
+
def add_log_entry(msg)
|
188
|
+
self.log_history << msg.merge(c_at: ::Time.now)
|
189
|
+
end
|
190
|
+
|
191
|
+
def add_status_log(message, tasklist = nil)
|
192
|
+
self.status_log << { timestamp: ::Time.now, tasklist: tasklist, text: message }.cleanup
|
193
|
+
end
|
194
|
+
|
195
|
+
def status_label(status_entry)
|
196
|
+
"#{status_entry[:tasklist].last rescue nil}#{status_entry[:text] rescue nil}"
|
197
|
+
end
|
198
|
+
|
199
|
+
end
|
200
|
+
```
|
201
|
+
|
202
|
+
Work items that are file-based can derive from the ::Libis::Workflow::FileItem class:
|
203
|
+
|
204
|
+
```ruby
|
205
|
+
|
206
|
+
require 'libis/workflow'
|
207
|
+
|
208
|
+
class MyFileItem < ::Libis::Workflow::FileItem
|
209
|
+
|
210
|
+
def initialize(file)
|
211
|
+
filename = file
|
212
|
+
super
|
213
|
+
end
|
214
|
+
|
215
|
+
def filesize
|
216
|
+
properties[:size]
|
217
|
+
end
|
218
|
+
|
219
|
+
def fixity_check(checksum)
|
220
|
+
properties[:checksum] == checksum
|
221
|
+
end
|
222
|
+
|
223
|
+
end
|
224
|
+
```
|
225
|
+
|
226
|
+
or include the ::Libis::Workflow::Base::FileItem module:
|
227
|
+
|
228
|
+
```ruby
|
229
|
+
|
230
|
+
require 'libis/workflow'
|
231
|
+
|
232
|
+
class MyFileItem < MyWorkItem
|
233
|
+
include ::Libis::Workflow::FileItem
|
234
|
+
|
235
|
+
def initialize(file)
|
236
|
+
filename = file
|
237
|
+
super
|
238
|
+
end
|
239
|
+
|
240
|
+
def filesize
|
241
|
+
properties[:size]
|
242
|
+
end
|
243
|
+
|
244
|
+
def fixity_check(checksum)
|
245
|
+
properties[:checksum] == checksum
|
246
|
+
end
|
247
|
+
|
248
|
+
end
|
249
|
+
```
|
250
|
+
|
251
|
+
|
252
|
+
|
253
|
+
## Tasks
|
254
|
+
|
255
|
+
Tasks should inherit from ::Libis::Workflow::Task and specify the actions it wants to
|
256
|
+
perform on each work item:
|
257
|
+
|
258
|
+
```ruby
|
259
|
+
|
260
|
+
class MyTask < ::Libis::Workflow::Task
|
261
|
+
|
262
|
+
def process_item(item)
|
263
|
+
if do_something(item)
|
264
|
+
info "Did something"
|
265
|
+
else
|
266
|
+
raise ::Libis::WorkflowError, "Something went wrong"
|
267
|
+
end
|
268
|
+
rescue Exception => e
|
269
|
+
error "Fatal problem, aborting"
|
270
|
+
raise ::Libis::WorkflowAbort, "Fatal problem"
|
271
|
+
ensure
|
272
|
+
item
|
273
|
+
end
|
274
|
+
|
275
|
+
end
|
276
|
+
```
|
277
|
+
|
278
|
+
As seen above, the task should define a method called process_item that takes one argument. The argument will be a
|
279
|
+
reference to the work item that it needs to perform an action on. The task has several option to progress after
|
280
|
+
performing its actions:
|
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.
|
283
|
+
* raise a ::Libis::WorkflowError. Indicates that something went wrong during the processing of the item. The item's
|
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.
|
287
|
+
* raise a ::Libis::WorkflowAbort. A severe and fatal error has occured. Processing will abort immediately and the
|
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.
|
290
|
+
* raise any other Exception. Should be avoided, but if it happens nevertheless, it will cause the item to fail for the
|
291
|
+
given task and the exception message to be logged in the error log. It will not attempt to process the other items.
|
292
|
+
|
293
|
+
### Controlling behavior with parameters
|
294
|
+
|
295
|
+
You have some options to control how the task will behave in special cases. These are controlled using parameters on
|
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
|
297
|
+
help of workflow input parameters and run options.
|
298
|
+
|
299
|
+
#### Preventing any logging output from the task
|
300
|
+
|
301
|
+
Logging output can be blocked on a task-by-task basis by setting the 'quiet' parameter to true. Probably not usefull
|
302
|
+
except for the Analyzer task where the parameter is fixed to true. Logging output would otherwise intervene with the
|
303
|
+
log summary processing performed by the task.
|
304
|
+
|
305
|
+
#### Performing an action on the work item and all child items recursively
|
306
|
+
|
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.
|
309
|
+
|
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
|
318
|
+
|
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.
|
325
|
+
|
326
|
+
### Pre- and postprocessing
|
327
|
+
|
328
|
+
The default implementation of 'process' is to call 'pre_process' and then call 'process_item' on each child item,
|
329
|
+
followed by calling 'post_process'. The methods 'pre_process' and 'post_process' are no-operation methods by default,
|
330
|
+
but can be overwritten if needed.
|
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
|
+
|
339
|
+
### Convenience functions
|
340
|
+
|
341
|
+
#### get_root_item()
|
342
|
+
|
343
|
+
Returns the work item that the workflow started with (and is the root/grand parent of all work items in the ingest run).
|
344
|
+
|
345
|
+
#### get_work_dir()
|
346
|
+
|
347
|
+
Returns the work directory as configured for the current ingest run. The work directory can be used as scrap directory
|
348
|
+
for creating derived files that can be added as work items to the current flow or for downloading files that will be
|
349
|
+
processed later. The work directory is not automaticaly cleaned up, which is considered a task for the workflow implementation.
|
350
|
+
|
351
|
+
#### capture_cmd(cmd, *args)
|
352
|
+
|
353
|
+
Allows the task to run an external command-line program and capture it's stdout and stderr output at the same time. The
|
354
|
+
first argument is mandatory and should be the command-line program that has to be executed. An arbitrary number of
|
355
|
+
command-line arguments may follow.
|
356
|
+
|
357
|
+
The return value is an array with three elements: the status code returned by the command, the stdout string and the
|
358
|
+
stderr string.
|
359
|
+
|
360
|
+
#### names()
|
361
|
+
|
362
|
+
An array of strings with the hierarchical path of tasks leading to the current task. Can be usefull for log messages.
|
363
|
+
The method 'namepath' returns a '/' separated path of tasks.
|
364
|
+
|
365
|
+
#### (debug/info/warn/error/fatal)(message, *args)
|
366
|
+
|
367
|
+
Convenience function for creating log entries. The logger set in ::Libis::Workflow::Config is used to dump log messages.
|
368
|
+
|
369
|
+
The first argument is mandatory and can be:
|
370
|
+
* an integer. The integer is used to look up the message text in ::Libis::Workflow::MessageRegistry.
|
371
|
+
* a static string. The message text is used as-is.
|
372
|
+
* a string with placement holders as used in String#%. Args can either be an array or a hash. See also Kernel#sprintf.
|
373
|
+
|
374
|
+
The log message is logged to the general logging and attached to the current work item (workitem) unless another
|
375
|
+
work item is passed as first argument after the message.
|
376
|
+
|
377
|
+
#### check_item_type(klass, item = nil)
|
378
|
+
|
379
|
+
Checks if the work item is of the given class. 'workitem' is checked if the item argument is not present. If the check
|
380
|
+
fails a Runtime exception is thrown which will cause the task to abort if not catched.
|
381
|
+
|
382
|
+
#### item_type?(klass, item = nil)
|
383
|
+
|
384
|
+
A less severe variant version of check_item_type which returns a boolean (false if failed).
|
385
|
+
|
386
|
+
#### to_status(status)
|
387
|
+
|
388
|
+
Simply prepends the status text with the current task name. The output of this function is typically what the work item
|
389
|
+
status field should be set at.
|
390
|
+
|
391
|
+
## Contributing
|
392
|
+
|
393
|
+
1. Fork it ( https://github.com/libis/workflow/fork )
|
394
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
395
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
396
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
397
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -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,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
|