libis-workflow 2.0.beta.11 → 2.0.beta.12
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +24 -17
- data/lib/libis/workflow/base/job.rb +85 -0
- data/lib/libis/workflow/base/run.rb +9 -7
- data/lib/libis/workflow/base/workflow.rb +6 -34
- data/lib/libis/workflow/job.rb +26 -0
- data/lib/libis/workflow/run.rb +2 -2
- data/lib/libis/workflow/version.rb +1 -1
- data/lib/libis/workflow/worker.rb +10 -10
- data/lib/libis/workflow/workflow.rb +1 -8
- data/lib/libis/workflow.rb +2 -0
- data/spec/workflow_spec.rb +13 -2
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3baa19f0fbc05d8254835124a68bf02dff63952d
|
4
|
+
data.tar.gz: 9a6f33b1e6de7ee1d699aaaca71e80a2194b1d9b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dd107fb0efd65099dda2c0215d93ad75fde65c0a2e3271f87ce505157ea1b1f321874d426f63a315214e3c09ba3ca3dc3d2f7d620edcdc02c16292912b38df41
|
7
|
+
data.tar.gz: 61199cfae002d01666ae76d76c2e5acdca3c837d99c59f57da0a972d9c21bdb011e59a89ebda3373f9b6387518cc0673f5d9282bf2516a72f7da5983cad36804
|
data/README.md
CHANGED
@@ -42,12 +42,12 @@ provided. It contains all the basic logic required for proper configuration and
|
|
42
42
|
implementation is provided in the class ::Libis::Workflow::Workflow for your convenience to be used as-is or to derive
|
43
43
|
your own from.
|
44
44
|
|
45
|
-
The
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
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
51
|
|
52
52
|
One tasks is predefined:
|
53
53
|
::Libis::Workflow::Tasks::Analyzer - analyzes the workflow run and summarizes the results. It is always included as the
|
@@ -67,22 +67,29 @@ You should start by including the following line in your source code:
|
|
67
67
|
This will load all of the Libis Workflow framework into your environment, but including only the required parts is OK as
|
68
68
|
well. This is shown in the examples below.
|
69
69
|
|
70
|
-
### Workflows
|
70
|
+
### Workflows and Jobs
|
71
71
|
|
72
72
|
An implementation of ::Libis::Workflow::Base::Workflow contains the definition of a workflow. Once instantiated, it can
|
73
|
-
be run by calling the '
|
74
|
-
configure it and call the 'run' method on it. The Workflow constructor
|
75
|
-
by calling the 'configure' method with the workflow configuration as an
|
76
|
-
as argument.
|
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
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
|
+
|
78
87
|
#### Workflow configuration
|
79
88
|
|
80
89
|
A workflow configuration is a Hash with:
|
81
90
|
* name: String to identify the workflow
|
82
91
|
* description: String with detailed textual information
|
83
92
|
* tasks: Array of task descriptions
|
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.
|
86
93
|
* input: Hash with input variable definitions
|
87
94
|
|
88
95
|
##### Task description
|
@@ -108,8 +115,8 @@ the chapter on 'Tasks' below for more information on tasks.
|
|
108
115
|
|
109
116
|
##### Input variable definition
|
110
117
|
|
111
|
-
The input variables define parameters for the workflow. When a
|
112
|
-
input
|
118
|
+
The input variables define parameters for the workflow. When a job is executed, it can provide values for any of these
|
119
|
+
input variables and the workflow run will use the new values instead of the defaults.
|
113
120
|
|
114
121
|
The key of the input Hash is the unique name of the variable. The value is another Hash with the parameter definition.
|
115
122
|
See ::Libis::Tools::Parameter for the content of this Hash.
|
@@ -122,8 +129,8 @@ if absent.
|
|
122
129
|
|
123
130
|
#### Run-time configuration
|
124
131
|
|
125
|
-
The '
|
126
|
-
previous chapter.
|
132
|
+
The job's 'execute' method takes an optional Hash as argument which will complement and override the options Hash
|
133
|
+
described in the previous chapter.
|
127
134
|
|
128
135
|
Once the workflow is configured and the root work item instantiated, the method will run each top-level task on the root
|
129
136
|
work item in sequence until all tasks have completed successfully or a task has failed.
|
@@ -0,0 +1,85 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'libis/tools/parameter'
|
4
|
+
|
5
|
+
module Libis
|
6
|
+
module Workflow
|
7
|
+
module Base
|
8
|
+
|
9
|
+
# This is the base module for Jobs.
|
10
|
+
#
|
11
|
+
# This module lacks the implementation for the data attributes. It functions as an interface that describes the
|
12
|
+
# common functionality regardless of the storage implementation. These attributes require some implementation:
|
13
|
+
#
|
14
|
+
# - name: [String] the name of the Job. The name will be used to identify the job. Each time a job is executed,
|
15
|
+
# a Run will be created for the associated workflow. The Run will get a name that starts with the job name
|
16
|
+
# and ends with the date and time the Run was first started. As such this name attribute serves as an
|
17
|
+
# identifier and should be treated as such. If possible it should be unique.
|
18
|
+
# - description: [String] optional information about the job.
|
19
|
+
# - workflow: [Object] the workflow containing the tasks that need to run.
|
20
|
+
# - run_obj: [String] the full class name of the Run implementation object that should be created when the
|
21
|
+
# Job is executed.
|
22
|
+
# - input: [Hash] workflow input parameter values. Each input parameter of the workflow can be set by the entries
|
23
|
+
# in this Hash.
|
24
|
+
#
|
25
|
+
# A minimal in-memory implementation could be:
|
26
|
+
#
|
27
|
+
# class Job
|
28
|
+
# include ::Libis::Workflow::Base::Job
|
29
|
+
#
|
30
|
+
# attr_accessor :name, :description, :workflow, :run_object, :input
|
31
|
+
#
|
32
|
+
# def initialize
|
33
|
+
# @name = ''
|
34
|
+
# @description = ''
|
35
|
+
# @input = Hash.new
|
36
|
+
# @workflow = ::Libis::Workflow::Workflow.new
|
37
|
+
# @run_object = ::Libis::Workflow::Run.new
|
38
|
+
# end
|
39
|
+
#
|
40
|
+
# end
|
41
|
+
#
|
42
|
+
module Job
|
43
|
+
|
44
|
+
def run_name(timestamp = Time.now)
|
45
|
+
"#{self.name}-#{timestamp.strftime('%Y%m%d%H%M%S')}"
|
46
|
+
end
|
47
|
+
|
48
|
+
def configure(cfg = {})
|
49
|
+
self.name ||= ''
|
50
|
+
self.description ||= ''
|
51
|
+
self.input ||= {}
|
52
|
+
|
53
|
+
self.name = cfg[:name] if cfg.has_key?(:name)
|
54
|
+
self.description = cfg[:description] if cfg.has_key?(:description)
|
55
|
+
self.workflow = cfg[:workflow] if cfg.has_key?(:workflow)
|
56
|
+
self.run_object = cfg[:run_object] if cfg.has_key?(:run_object)
|
57
|
+
self.input.merge!(cfg[:input] || {})
|
58
|
+
end
|
59
|
+
|
60
|
+
# noinspection RubyResolve
|
61
|
+
# @param [Hash] opts optional extra conguration values for this particular run
|
62
|
+
def execute(opts = {})
|
63
|
+
run = self.create_run_object
|
64
|
+
raise RuntimeError.new "Could not create instance of run object '#{self.run_object}'" unless run
|
65
|
+
|
66
|
+
run.job = self
|
67
|
+
run.options = self.input.merge(opts)
|
68
|
+
run.save
|
69
|
+
|
70
|
+
run.run
|
71
|
+
|
72
|
+
run
|
73
|
+
end
|
74
|
+
|
75
|
+
protected
|
76
|
+
|
77
|
+
# noinspection RubyResolve
|
78
|
+
def create_run_object
|
79
|
+
self.run_object.constantize.new
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -14,7 +14,7 @@ module Libis
|
|
14
14
|
# common functionality regardless of the storage implementation. These attributes require some implementation:
|
15
15
|
#
|
16
16
|
# - start_date: [Time] the timestamp of the execution of the run
|
17
|
-
# -
|
17
|
+
# - job: [Object] a reference to the Job this Run belongs to
|
18
18
|
#
|
19
19
|
# Note that ::Libis::Workflow::Base::WorkItem is a parent module and therefore requires implementation of the
|
20
20
|
# attributes of that module too.
|
@@ -33,7 +33,7 @@ module Libis
|
|
33
33
|
end
|
34
34
|
|
35
35
|
def name
|
36
|
-
self.
|
36
|
+
self.job.run_name(self.start_date)
|
37
37
|
end
|
38
38
|
|
39
39
|
def names
|
@@ -44,16 +44,18 @@ module Libis
|
|
44
44
|
self.name
|
45
45
|
end
|
46
46
|
|
47
|
+
def workflow
|
48
|
+
self.job.workflow
|
49
|
+
end
|
50
|
+
|
47
51
|
# Execute the workflow.
|
48
|
-
|
49
|
-
# parameters.
|
50
|
-
def run(opts = {})
|
52
|
+
def run
|
51
53
|
|
52
54
|
self.start_date = Time.now
|
53
55
|
|
54
|
-
self.options = workflow.prepare_input(self.options
|
56
|
+
self.options = workflow.prepare_input(self.options)
|
55
57
|
|
56
|
-
self.tasks =
|
58
|
+
self.tasks = workflow.tasks(self)
|
57
59
|
configure_tasks self.options
|
58
60
|
|
59
61
|
self.status = :STARTED
|
@@ -19,8 +19,6 @@ module Libis
|
|
19
19
|
# - config: [Hash] detailed configuration for the workflow. The application assumes it behaves as a Hash and will
|
20
20
|
# access it with [], merge! and delete methods. If your implementation decides to implement it with another
|
21
21
|
# object, it should implement above methods. The config Hash requires the following keys:
|
22
|
-
# - run_object: [String] the full class name of the Run implementation object that should be created when the
|
23
|
-
# Workflow is executed.
|
24
22
|
# - input: [Hash] all input parameter definitions where the key is the parameter name and the value is another
|
25
23
|
# Hash with arguments for the parameter definition. It typically contains the following arguments:
|
26
24
|
# - default: default value if no value specified when the workflow is executed
|
@@ -46,6 +44,9 @@ module Libis
|
|
46
44
|
# ::Libis::Workflow::Task class will be instatiated. It will do nothing itself, but will execute the
|
47
45
|
# subtasks on the item(s). In such case a 'name' is mandatory.
|
48
46
|
#
|
47
|
+
# These values should be set by calling the #configure method which takes a Hash as argument with :name,
|
48
|
+
# :description, :input and :tasks keys.
|
49
|
+
#
|
49
50
|
# A minimal in-memory implementation could be:
|
50
51
|
#
|
51
52
|
# class Workflow
|
@@ -55,7 +56,7 @@ module Libis
|
|
55
56
|
#
|
56
57
|
# def initialize
|
57
58
|
# @name = ''
|
58
|
-
# @
|
59
|
+
# @description = ''
|
59
60
|
# @config = Hash.new
|
60
61
|
# end
|
61
62
|
#
|
@@ -105,44 +106,15 @@ module Libis
|
|
105
106
|
{}
|
106
107
|
end
|
107
108
|
|
108
|
-
def run_name(timestamp = Time.now)
|
109
|
-
"#{self.workflow.name}-#{timestamp.strftime('%Y%m%d%H%M%S')}"
|
110
|
-
end
|
111
|
-
|
112
|
-
def perform(opts = {})
|
113
|
-
self.run opts
|
114
|
-
end
|
115
|
-
|
116
|
-
def create_run_object
|
117
|
-
self.config[:run_object].constantize.new
|
118
|
-
end
|
119
|
-
|
120
|
-
# @param [Hash] opts
|
121
|
-
def run(opts = {})
|
122
|
-
|
123
|
-
run_object = self.create_run_object
|
124
|
-
raise RuntimeError.new "Could not create instance of run object '#{self.config[:run_object]}'" unless run_object
|
125
|
-
|
126
|
-
run_object.workflow = self
|
127
|
-
run_object.options = opts
|
128
|
-
run_object.save
|
129
|
-
|
130
|
-
run_object.run opts
|
131
|
-
|
132
|
-
run_object
|
133
|
-
end
|
134
|
-
|
135
109
|
# @param [Hash] opts
|
136
110
|
def prepare_input(opts)
|
137
111
|
options = opts.dup
|
138
112
|
self.input.each do |key, parameter|
|
139
|
-
key
|
140
|
-
# provided in opts
|
141
|
-
options[key] = parameter[:default] unless options.has_key? key
|
113
|
+
options[key] = parameter[:default] unless options.has_key?(key)
|
142
114
|
options[key] = parameter.parse(options[key])
|
143
115
|
propagate_to = []
|
144
116
|
propagate_to = parameter[:propagate_to] if parameter[:propagate_to].is_a? Array
|
145
|
-
propagate_to = parameter[:propagate_to].split(
|
117
|
+
propagate_to = parameter[:propagate_to].split(/[\s,;]+/) if parameter[:propagate_to].is_a? String
|
146
118
|
propagate_to.each do |target|
|
147
119
|
task_name, param_name = target.split('#')
|
148
120
|
param_name ||= key
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'libis/workflow/base/job'
|
4
|
+
require 'libis/workflow/workflow'
|
5
|
+
require 'libis/workflow/run'
|
6
|
+
|
7
|
+
module Libis
|
8
|
+
module Workflow
|
9
|
+
|
10
|
+
class Job
|
11
|
+
include ::Libis::Workflow::Base::Job
|
12
|
+
|
13
|
+
attr_accessor :name, :description, :workflow, :run_object, :input
|
14
|
+
|
15
|
+
def initialize
|
16
|
+
@name = ''
|
17
|
+
@description = ''
|
18
|
+
@input = Hash.new
|
19
|
+
@workflow = ::Libis::Workflow::Workflow.new
|
20
|
+
@run_object = ::Libis::Workflow::Run.new
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
data/lib/libis/workflow/run.rb
CHANGED
@@ -12,11 +12,11 @@ module Libis
|
|
12
12
|
class Run < ::Libis::Workflow::WorkItem
|
13
13
|
include ::Libis::Workflow::Base::Run
|
14
14
|
|
15
|
-
attr_accessor :start_date, :
|
15
|
+
attr_accessor :start_date, :job
|
16
16
|
|
17
17
|
def initialize
|
18
18
|
@start_date = Time.now
|
19
|
-
@
|
19
|
+
@job = nil
|
20
20
|
super
|
21
21
|
end
|
22
22
|
|
@@ -2,6 +2,6 @@
|
|
2
2
|
|
3
3
|
module Libis
|
4
4
|
module Workflow
|
5
|
-
VERSION = '2.0.beta.
|
5
|
+
VERSION = '2.0.beta.12' unless const_defined? :VERSION # the guard is against a redefinition warning that happens on Travis
|
6
6
|
end
|
7
7
|
end
|
@@ -10,30 +10,30 @@ module Libis
|
|
10
10
|
class Worker
|
11
11
|
include Sidekiq::Worker
|
12
12
|
|
13
|
-
def perform(
|
14
|
-
|
13
|
+
def perform(job_config, options = {})
|
14
|
+
job = self.class.configure(job_config, options)
|
15
15
|
options[:interactive] = false
|
16
|
-
|
16
|
+
job.execute options
|
17
17
|
end
|
18
18
|
|
19
|
-
def self.configure(
|
19
|
+
def self.configure(job_config, options = {})
|
20
20
|
log_path = options.delete :log_path
|
21
21
|
if log_path
|
22
22
|
Config.logger = ::Logger.new(
|
23
|
-
File.join(log_path, "#{
|
23
|
+
File.join(log_path, "#{job_config[:name]}.log"),
|
24
24
|
(options.delete(:log_shift_age) || 'daily'),
|
25
25
|
(options.delete(:log_shift_size) || 1024 ** 2)
|
26
26
|
)
|
27
27
|
Config.logger.formatter = ::Logger::Formatter.new
|
28
28
|
Config.logger.level = ::Logger::DEBUG
|
29
29
|
end
|
30
|
-
|
30
|
+
get_job(job_config)
|
31
31
|
end
|
32
32
|
|
33
|
-
def
|
34
|
-
|
35
|
-
|
36
|
-
|
33
|
+
def get_job(job_config)
|
34
|
+
job = ::Libis::Workflow::Job.new
|
35
|
+
job.configure job_config
|
36
|
+
job
|
37
37
|
end
|
38
38
|
|
39
39
|
end
|
@@ -1,12 +1,5 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
|
-
require 'backports/rails/string'
|
4
|
-
require 'backports/rails/hash'
|
5
|
-
|
6
|
-
require 'libis/workflow/config'
|
7
|
-
require 'libis/workflow/task'
|
8
|
-
require 'libis/workflow/tasks/analyzer'
|
9
|
-
|
10
3
|
require 'libis/workflow/base/workflow'
|
11
4
|
|
12
5
|
module Libis
|
@@ -19,7 +12,7 @@ module Libis
|
|
19
12
|
|
20
13
|
def initialize
|
21
14
|
@name = ''
|
22
|
-
@
|
15
|
+
@description = ''
|
23
16
|
@config = Hash.new
|
24
17
|
end
|
25
18
|
|
data/lib/libis/workflow.rb
CHANGED
@@ -12,6 +12,7 @@ module Libis
|
|
12
12
|
autoload :FileItem, 'libis/workflow/base/file_item'
|
13
13
|
autoload :DirItem, 'libis/workflow/base/dir_item'
|
14
14
|
autoload :Logger, 'libis/workflow/base/logger'
|
15
|
+
autoload :Job, 'libis/workflow/base/job'
|
15
16
|
autoload :Run, 'libis/workflow/base/run'
|
16
17
|
autoload :Workflow, 'libis/workflow/base/workflow'
|
17
18
|
end
|
@@ -21,6 +22,7 @@ module Libis
|
|
21
22
|
autoload :DirItem, 'libis/workflow/dir_item'
|
22
23
|
|
23
24
|
autoload :Workflow, 'libis/workflow/workflow'
|
25
|
+
autoload :Job, 'libis/workflow/job'
|
24
26
|
autoload :Run, 'libis/workflow/run'
|
25
27
|
autoload :Task, 'libis/workflow/task'
|
26
28
|
|
data/spec/workflow_spec.rb
CHANGED
@@ -33,7 +33,6 @@ describe 'TestWorkflow' do
|
|
33
33
|
]
|
34
34
|
}
|
35
35
|
],
|
36
|
-
run_object: 'TestRun',
|
37
36
|
input: {
|
38
37
|
dirname: {default: '.', propagate_to: 'CollectFiles#location'},
|
39
38
|
checksum_type: {default: 'SHA1', propagate_to: 'ChecksumTester'}
|
@@ -42,8 +41,20 @@ describe 'TestWorkflow' do
|
|
42
41
|
workflow
|
43
42
|
}
|
44
43
|
|
44
|
+
let(:job) {
|
45
|
+
job = ::Libis::Workflow::Job.new
|
46
|
+
job.configure(
|
47
|
+
name: 'TestJob',
|
48
|
+
description: 'Job for testing',
|
49
|
+
workflow: workflow,
|
50
|
+
run_object: 'TestRun',
|
51
|
+
input: {dirname: dirname, checksum_type: 'SHA256'},
|
52
|
+
)
|
53
|
+
job
|
54
|
+
}
|
55
|
+
|
45
56
|
let!(:run) {
|
46
|
-
|
57
|
+
job.execute
|
47
58
|
}
|
48
59
|
|
49
60
|
it 'should contain three tasks' do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: libis-workflow
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.beta.
|
4
|
+
version: 2.0.beta.12
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kris Dekeyser
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-11-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -127,6 +127,7 @@ files:
|
|
127
127
|
- lib/libis/workflow/base.rb
|
128
128
|
- lib/libis/workflow/base/dir_item.rb
|
129
129
|
- lib/libis/workflow/base/file_item.rb
|
130
|
+
- lib/libis/workflow/base/job.rb
|
130
131
|
- lib/libis/workflow/base/logger.rb
|
131
132
|
- lib/libis/workflow/base/run.rb
|
132
133
|
- lib/libis/workflow/base/work_item.rb
|
@@ -134,6 +135,7 @@ files:
|
|
134
135
|
- lib/libis/workflow/config.rb
|
135
136
|
- lib/libis/workflow/dir_item.rb
|
136
137
|
- lib/libis/workflow/file_item.rb
|
138
|
+
- lib/libis/workflow/job.rb
|
137
139
|
- lib/libis/workflow/message_registry.rb
|
138
140
|
- lib/libis/workflow/run.rb
|
139
141
|
- lib/libis/workflow/task.rb
|
@@ -173,7 +175,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
173
175
|
version: 1.3.1
|
174
176
|
requirements: []
|
175
177
|
rubyforge_project:
|
176
|
-
rubygems_version: 2.
|
178
|
+
rubygems_version: 2.5.0
|
177
179
|
signing_key:
|
178
180
|
specification_version: 4
|
179
181
|
summary: LIBIS Workflow framework.
|