libis-workflow 2.0.beta.11 → 2.0.beta.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +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.
|