libis-workflow 2.0.12 → 2.0.13

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: f79b538ba0bf95e113d0f5fcf24abf11d924436a
4
- data.tar.gz: 93e10a182e7788367a63f5e520b861027d6eea68
3
+ metadata.gz: 391fa63e8c66d517802a33270a23090e71861051
4
+ data.tar.gz: d78da40fa5ebdca1174805ec76aa3c5b4e62ddcf
5
5
  SHA512:
6
- metadata.gz: d71d3a5142ecae99d83f35dab0efcc94ecc693ec2117f4970efa3a46d3c0f11ec423a77af8ad8d4efb1ace566e2ad7716538a6bfcf77f8483f59879f1dbe0f1d
7
- data.tar.gz: 9baa84b4a68faedbff5723123ce1dc2c8863cce3558bfe19c7ec5b1f9a528cad0626890f4b38b6d4a2f1761c66c18d32000f995cfb42795ae2c38ea3e8ad80c5
6
+ metadata.gz: 355050d00564e301721e794c4ef4effdd3c8626ed1e98d7c572942dca121769c4baf4468513391b92d4e917f0d63d84e10294d4d7ec2f50d4ec3eb2155bc4eb5
7
+ data.tar.gz: 81a05c1532b13641e3d48f0a4f37bdedb0e0ec52fc4cfc5641aef51814792546dbd3baf24a6bee1b3534688ddeb8f53311e9481beab3027b2afeba4f22fee61d
data/README.md CHANGED
@@ -44,7 +44,7 @@ implementation is provided in the class ::Libis::Workflow::Workflow for your con
44
44
  your own from.
45
45
 
46
46
  The Job class is responsible for instantiating a run-time workflow execution object - a Run - that captures the
47
- configuration, logs and workitems generated while executing the tasks. Essential logic is provided in the module
47
+ configuration and workitems generated while executing the tasks. Essential logic is provided in the module
48
48
  ::Libis::Workflow::Base::Run with a simple in-memory implementation in ::Libis::Workflow::Run. The run object's class
49
49
  name has to be provided to the job configuration so that the job can instantiate the correct object. The run object
50
50
  will be able to execute the tasks in proper order on all the WorkItems supplied/collected. Each task can be implemented
@@ -99,15 +99,17 @@ is a Hash with:
99
99
  ::Libis::Tools::Parameter class for this.
100
100
 
101
101
  The ::Libis::Workflow::Task base class allready defines the following parameters:
102
- * quiet: Prevent generating log output. Default: false
103
102
  * recursive: Run the task on all subitems recursively. Default: false
103
+ * abort_recursion_on_failure: Stop processing items recursively if one item fails. Default: false
104
104
  * retry_count: Number of times to retry the task. Default: 0
105
105
  * retry_interval: Number of seconds to wait between retries. Default: 10
106
106
 
107
107
  If 'class' is not present, the default '::Libis::Workflow::TaskGroup' with the given name will be instantiated, which
108
- performs each sub-task on the item. If the task is configured to be recursive, it will iterate over the child items and
109
- perform each sub-task on each of the child items. If a 'class' value is given, an instance of that class will be created
110
- and the task will be handed the work item to process on. See the chapter on 'Tasks' below for more information on tasks.
108
+ performs each sub-task on the item.
109
+
110
+ If the task is configured to be recursive, it will iterate over the child items and perform each sub-task on each of
111
+ the child items. If a 'class' value is given, an instance of that class will be created and the task will be handed
112
+ the work item to process on. See the chapter on 'Tasks' below for more information on tasks.
111
113
 
112
114
  Note that a task with custom processing will not execute sub-tasks. If you configured a processing task with subtasks
113
115
  an exception will be thrown when trying to execute the job.
@@ -165,7 +167,6 @@ or if a custom storage implementation is desired, a number of data items and met
165
167
  stored_attribute :items
166
168
  stored_attribute :options
167
169
  stored_attribute :properties
168
- stored_attribute :log_history
169
170
  stored_attribute :status_log
170
171
  stored_attribute :summary
171
172
 
@@ -174,23 +175,14 @@ or if a custom storage implementation is desired, a number of data items and met
174
175
  self.items = []
175
176
  self.options = {}
176
177
  self.properties = {}
177
- self.log_history = []
178
178
  self.status_log = []
179
179
  self.summary = {}
180
180
  end
181
181
 
182
182
  protected
183
183
 
184
- def add_log_entry(msg)
185
- self.log_history << msg.merge(c_at: ::Time.now)
186
- end
187
-
188
- def add_status_log(message, tasklist = nil)
189
- self.status_log << { timestamp: ::Time.now, tasklist: tasklist, text: message }.cleanup
190
- end
191
-
192
- def status_label(status_entry)
193
- "#{status_entry[:tasklist].last rescue nil}#{status_entry[:text] rescue nil}"
184
+ def add_status_log(info)
185
+ self.status_log << info
194
186
  end
195
187
 
196
188
  end
@@ -14,11 +14,6 @@ module Libis
14
14
  # This module lacks the implementation for the data attributes. It functions as an interface that describes the
15
15
  # common functionality regardless of the storage implementation. These attributes require some implementation:
16
16
  #
17
- # - status: [Symbol] the status field. Each task sets the status of the items it works on. Before starting processing
18
- # the status is set to "#{task_name}Started". After successfull processing it is set to "#{task_name}Done" and if
19
- # the task failed, it is set to "#{task_name}Failed". The status field can be used to perform real-time
20
- # monitoring, reporting and error-recovery or restart of the ingest.
21
- # The initial value for this attribute is :START.
22
17
  # - parent: [Object|nil] a link to a parent work item. Work items can be organized in any hierarchy you think is
23
18
  # relevant for your workflow (e.g. directory[/directory...]/file/line or library/section/book/page). Of course
24
19
  # hierarchies are not mandatory.
@@ -28,9 +23,6 @@ module Libis
28
23
  # - properties: [Hash] a set of properties, typically collected during the workflow processing and used to store
29
24
  # final or intermediate resulst of tasks. The ::Lias::Ingester::FileItem module uses this attribute to store the
30
25
  # properties (e.g. size, checksum, ...) of the file it represents.
31
- # - log_history: [Array] a list of all logging messages collected for this work item. Whenever a task logs a message
32
- # it will automatically be registered for the work item that it is processing or for the work item that was
33
- # supplied as the first argument.
34
26
  # - status_log: [Array] a list of all status changes the work item went through.
35
27
  # - summary: [Hash] collected statistics about the ingest for the work item and its children. This structure will
36
28
  # be filled in by the included task ::Lias::Ingester::Tasks::Analyzer wich is appended to the workflow by default.
@@ -41,7 +33,7 @@ module Libis
41
33
  # attr_accessor :parent
42
34
  # attr_accessor :items
43
35
  # attr_accessor :options, :properties
44
- # attr_accessor :log_history, :status_log
36
+ # attr_accessor :status_log
45
37
  # attr_accessor :summary
46
38
  #
47
39
  # def initialize
@@ -49,21 +41,16 @@ module Libis
49
41
  # self.items = []
50
42
  # self.options = {}
51
43
  # self.properties = {}
52
- # self.log_history = []
53
44
  # self.status_log = []
54
45
  # self.summary = {}
55
46
  # end
56
47
  #
57
48
  # protected
58
49
  #
59
- # ## Methods below should be adapted to match the implementation of the log arrays
50
+ # ## Method below should be adapted to match the implementation of the status array
60
51
  #
61
- # def add_log_entry(msg)
62
- # self.log_history << msg.merge(c_at: ::Time.now)
63
- # end
64
- #
65
- # def add_status_log(message, tasklist = nil)
66
- # self.status_log << { c_at: ::Time.now, tasklist: tasklist, text: message }.cleanup
52
+ # def add_status_log(info)
53
+ # self.status_log << info
67
54
  # end
68
55
  #
69
56
  #
@@ -34,8 +34,8 @@ module Libis
34
34
  # - tasks: [Array] a list of subtask defintions for this task.
35
35
  #
36
36
  # Additionally the task definition Hash may specify values for any other parameter that the task knows of.
37
- # All tasks have parameters 'quiet', 'recursive', 'retry_count' and 'retry_interval'. For more
38
- # information about these see the documentation of the task class.
37
+ # All tasks have some fixed parameters. For more information about these see the documentation of
38
+ # the task class.
39
39
  #
40
40
  # A task definition does not require to have a 'class' entry. If not present the default
41
41
  # ::Libis::Workflow::TaskGroup class will be instatiated. It will do nothing itself, but will execute the
@@ -22,10 +22,16 @@ module Libis
22
22
 
23
23
  # Changes the status of the object. The status changed is logged in the status_log with the current timestamp.
24
24
  #
25
- # @param [Array] x Array with status and task
26
- def status=(x)
27
- s, task = x
28
- self.add_status_log(task: task, status: s)
25
+ # @param [String] task namepath of the task
26
+ # @param [Symbol] status status to set
27
+ def set_status(task, status)
28
+ case status
29
+ when :STARTED
30
+ self.add_status_log(task: task, status: status)
31
+ else
32
+ log_entry = status_entry(task) || self.add_status_log(task: task, status: status)
33
+ log_entry[:status] = status
34
+ end
29
35
  self.save!
30
36
  end
31
37
 
@@ -73,6 +79,18 @@ module Libis
73
79
  STATUS[self.status(task)] <=> STATUS[state]
74
80
  end
75
81
 
82
+ # Update the progress of the working task
83
+ # @param [String] task namepath of the task
84
+ # @param [Integer] progress progress indicator (as <progress> of <max> or as % if <max> not set). Default: 0
85
+ # @param [Integer] max max count.
86
+ def status_progress(task, progress = 0, max = nil)
87
+ log_entry = self.status_entry(task)
88
+ log_entry ||= self.status_log.build(task: task)
89
+ log_entry[:progress] = progress
90
+ log_entry[:max] = max if max
91
+ self.save!
92
+ end
93
+
76
94
  protected
77
95
 
78
96
  # Get last known status entry for a given task
@@ -17,8 +17,8 @@ module Libis
17
17
 
18
18
  attr_accessor :parent, :name, :workitem
19
19
 
20
- parameter quiet: false, description: 'Prevent generating log output.'
21
20
  parameter recursive: false, description: 'Run the task on all subitems recursively.'
21
+ parameter abort_recursion_on_failure: false, description: 'Stop processing items recursively if one item fails.'
22
22
  parameter retry_count: 0, description: 'Number of times to retry the task if waiting for another process.'
23
23
  parameter retry_interval: 10, description: 'Number of seconds to wait between retries.'
24
24
 
@@ -124,23 +124,13 @@ module Libis
124
124
  def message(severity, msg, *args)
125
125
  taskname = self.namepath rescue nil
126
126
  self.set_application(taskname)
127
- item = self.workitem
127
+ item = self.workitem rescue nil
128
128
  item = args.shift if args.size > 0 and args[0].is_a?(::Libis::Workflow::Base::WorkItem)
129
- if item
130
- subject = nil
131
- begin
132
- subject = item.to_s
133
- subject = item.name
134
- subject = item.namepath
135
- rescue
136
- # do nothing
137
- end
138
- self.set_subject(subject)
139
- return unless super(severity, msg, *args)
140
- item.log_message(
141
- severity, msg.is_a?(Integer) ? {id: msg} : {text: (msg.to_s rescue '')}.merge(task: taskname), *args
142
- )
143
- end
129
+ subject = item.namepath rescue nil
130
+ subject ||= item.name rescue nil
131
+ subject ||= item.to_s rescue nil
132
+ self.set_subject(subject)
133
+ super(severity, msg, *args)
144
134
  end
145
135
 
146
136
  def logger
@@ -192,10 +182,14 @@ module Libis
192
182
  return unless items.size > 0
193
183
 
194
184
  status = Hash.new(0)
185
+ parent_item.status_progress(self.namepath, 0, items.count)
195
186
  items.each_with_index do |item, i|
196
187
  debug 'Processing subitem (%d/%d): %s', parent_item, i+1, items.size, item.to_s
197
188
  run_item item
198
- status[item.status(self.namepath)] += 1
189
+ parent_item.status_progress(self.namepath, i+1)
190
+ item_status = item.status(self.namepath)
191
+ status[item_status] += 1
192
+ break if parameter(:abort_recursion_on_failure) && item_status != :DONE
199
193
  end
200
194
 
201
195
  debug '%d of %d subitems passed', parent_item, status[:DONE], items.size
@@ -275,14 +269,10 @@ module Libis
275
269
  end
276
270
 
277
271
  def set_status(item, state)
278
- item.status = to_status(state)
272
+ item.set_status self.namepath, state
279
273
  state
280
274
  end
281
275
 
282
- def to_status(state)
283
- [state, self.namepath]
284
- end
285
-
286
276
  def check_item_type(klass, item = nil)
287
277
  item ||= self.workitem
288
278
  unless item.is_a? klass.to_s.constantize
@@ -38,11 +38,14 @@ module Libis
38
38
  return unless tasks.size > 0
39
39
 
40
40
  status = Hash.new(0)
41
+ item.status_progress(self.namepath, 0, tasks.count)
41
42
  tasks.each_with_index do |task, i|
42
43
  info 'Running subtask (%d/%d): %s', item, i+1, tasks.size, task.name
43
44
  task.run item
44
- status[item.status(task.namepath)] += 1
45
- break if parameter(:abort_on_failure) && item.status(task.namepath) != :DONE
45
+ item.status_progress(self.namepath, i+1)
46
+ item_status = item.status(task.namepath)
47
+ status[item_status] += 1
48
+ break if parameter(:abort_on_failure) && item_status != :DONE
46
49
  end
47
50
 
48
51
  substatus_check(status, item, 'task')
@@ -26,42 +26,6 @@ module Libis
26
26
 
27
27
  super
28
28
 
29
- recursive_run(item)
30
- self.workitem = item
31
-
32
- end
33
-
34
- private
35
-
36
- def recursive_run(item)
37
-
38
- item.properties['ingest_failed'] = item.check_status(:FAILED)
39
-
40
- item.summary = {}
41
- item.log_history.each do |log|
42
- level = log[:severity]
43
- item.summary[level.to_s] ||= 0
44
- item.summary[level.to_s] += 1
45
- end
46
-
47
- item.each do |i|
48
- recursive_run i
49
- i.summary.each do |level, count|
50
- item.summary[level] ||= 0
51
- item.summary[level] += (count || 0)
52
- end
53
- end
54
-
55
- rescue RuntimeError => ex
56
-
57
- self.workitem = item
58
- error 'Failed to analyze item: %s - %s', item, item.class, item.name
59
- error 'Exception: %s', item, ex.message
60
-
61
- ensure
62
-
63
- item.save!
64
-
65
29
  end
66
30
 
67
31
  end
@@ -1,5 +1,5 @@
1
1
  module Libis
2
2
  module Workflow
3
- VERSION = '2.0.12' unless const_defined? :VERSION # the guard is against a redefinition warning that happens on Travis
3
+ VERSION = '2.0.13' unless const_defined? :VERSION # the guard is against a redefinition warning that happens on Travis
4
4
  end
5
5
  end
@@ -11,7 +11,7 @@ module Libis
11
11
  attr_accessor :parent
12
12
  attr_accessor :items
13
13
  attr_accessor :options, :properties
14
- attr_accessor :log_history, :status_log
14
+ attr_accessor :status_log
15
15
  attr_accessor :summary
16
16
 
17
17
  def initialize
@@ -19,21 +19,15 @@ module Libis
19
19
  self.items = []
20
20
  self.options = {}
21
21
  self.properties = {}
22
- self.log_history = []
23
22
  self.status_log = []
24
23
  self.summary = {}
25
24
  end
26
25
 
27
26
  protected
28
27
 
29
- def add_log_entry(msg)
30
- # noinspection RubyResolve
31
- self.log_history << msg.merge(c_at: ::Time.now)
32
- end
33
-
34
28
  def add_status_log(info)
35
29
  # noinspection RubyResolve
36
- self.status_log << info.merge(timestamp: ::Time.now).cleanup
30
+ self.status_log << info
37
31
  end
38
32
 
39
33
  end
@@ -121,87 +121,35 @@ STR
121
121
  expect(o[/(?<=\] ).*/].strip).to eq sample_out[i].strip
122
122
  end
123
123
 
124
- expect(run.summary['DEBUG']).to eq 18
125
- expect(run.log_history.size).to eq 13
126
- expect(run.status_log.size).to eq 10
127
- expect(run.items.first.log_history.size).to eq 12
128
- expect(run.items.first.status_log.size).to eq 6
124
+ expect(run.status_log.size).to eq 5
125
+ expect(run.items.first.status_log.size).to eq 3
129
126
 
130
127
  [
131
- {task: 'Run', status: :STARTED},
132
- {task: 'CollectFiles', status: :STARTED},
133
- {task: 'CollectFiles', status: :DONE},
134
- {task: 'ProcessFiles', status: :STARTED},
135
- {task: 'ProcessFiles/ChecksumTester', status: :STARTED},
136
- {task: 'ProcessFiles/ChecksumTester', status: :DONE},
137
- {task: 'ProcessFiles/CamelizeName', status: :STARTED},
138
- {task: 'ProcessFiles/CamelizeName', status: :DONE},
139
- {task: 'ProcessFiles', status: :DONE},
140
- {task: 'Run', status: :DONE},
128
+ {task: 'Run', status: :DONE, progress: 2, max: 2},
129
+ {task: 'CollectFiles', status: :DONE, progress: 1, max: 1},
130
+ {task: 'ProcessFiles', status: :DONE, progress: 2, max: 2},
131
+ {task: 'ProcessFiles/ChecksumTester', status: :DONE, progress: 1, max: 1},
132
+ {task: 'ProcessFiles/CamelizeName', status: :DONE, progress: 1, max: 1},
141
133
  ].each_with_index do |h, i|
142
134
  h.keys.each { |key| expect(run.status_log[i][key]).to eq h[key] }
143
135
  end
144
136
 
145
137
  [
146
- {task: 'CollectFiles', status: :STARTED},
147
- {task: 'CollectFiles', status: :DONE},
148
- {task: 'ProcessFiles/ChecksumTester', status: :STARTED},
149
- {task: 'ProcessFiles/ChecksumTester', status: :DONE},
150
- {task: 'ProcessFiles/CamelizeName', status: :STARTED},
151
- {task: 'ProcessFiles/CamelizeName', status: :DONE},
138
+ {task: 'CollectFiles', status: :DONE, progress: 3, max: 3},
139
+ {task: 'ProcessFiles/ChecksumTester', status: :DONE, progress: 3, max: 3},
140
+ {task: 'ProcessFiles/CamelizeName', status: :DONE, progress: 3, max: 3},
152
141
  ].each_with_index do |h, i|
153
142
  h.keys.each { |key| expect(run.items.first.status_log[i][key]).to eq h[key] }
154
143
  end
155
144
 
156
145
  [
157
- {task: 'CollectFiles', status: :STARTED},
158
- {task: 'CollectFiles', status: :DONE},
159
- {task: 'ProcessFiles/ChecksumTester', status: :STARTED},
160
- {task: 'ProcessFiles/ChecksumTester', status: :DONE},
161
- {task: 'ProcessFiles/CamelizeName', status: :STARTED},
162
- {task: 'ProcessFiles/CamelizeName', status: :DONE},
146
+ {task: 'CollectFiles', status: :DONE, progress: nil, max: nil},
147
+ {task: 'ProcessFiles/ChecksumTester', status: :DONE, progress: nil, max: nil},
148
+ {task: 'ProcessFiles/CamelizeName', status: :DONE, progress: nil, max: nil},
163
149
  ].each_with_index do |h, i|
164
150
  h.keys.each { |key| expect(run.items.first.first.status_log[i][key]).to eq h[key] }
165
151
  end
166
152
 
167
- [
168
- {severity: 'INFO', task: 'Run', message: 'Ingest run started.'},
169
- {severity: 'INFO', task: 'Run', message: 'Running subtask (1/2): CollectFiles'},
170
- {severity: 'DEBUG', task: 'CollectFiles', message: 'Processing subitem (1/1): items'},
171
- {severity: 'DEBUG', task: 'CollectFiles', message: '1 of 1 subitems passed'},
172
- {severity: 'INFO', task: 'Run', message: 'Running subtask (2/2): ProcessFiles'},
173
- {severity: 'INFO', task: 'ProcessFiles', message: 'Running subtask (1/2): ChecksumTester'},
174
- {severity: 'DEBUG', task: 'ProcessFiles/ChecksumTester', message: 'Processing subitem (1/1): items'},
175
- {severity: 'DEBUG', task: 'ProcessFiles/ChecksumTester', message: '1 of 1 subitems passed'},
176
- {severity: 'INFO', task: 'ProcessFiles', message: 'Running subtask (2/2): CamelizeName'},
177
- {severity: 'DEBUG', task: 'ProcessFiles/CamelizeName', message: 'Processing subitem (1/1): items'},
178
- {severity: 'DEBUG', task: 'ProcessFiles/CamelizeName', message: '1 of 1 subitems passed'},
179
- {severity: 'INFO', task: 'ProcessFiles', message: 'Done'},
180
- {severity: 'INFO', task: 'Run', message: 'Done'},
181
- ].each_with_index do |h, i|
182
- h.keys.each { |key| expect(run.log_history[i][key]).to eq h[key] }
183
- end
184
-
185
- [
186
- {severity: 'DEBUG', task: 'CollectFiles', message: 'Processing subitem (1/3): test_dir_item.rb'},
187
- {severity: 'DEBUG', task: 'CollectFiles', message: 'Processing subitem (2/3): test_file_item.rb'},
188
- {severity: 'DEBUG', task: 'CollectFiles', message: 'Processing subitem (3/3): test_run.rb'},
189
- {severity: 'DEBUG', task: 'CollectFiles', message: '3 of 3 subitems passed'},
190
- {severity: 'DEBUG', task: 'ProcessFiles/ChecksumTester', message: 'Processing subitem (1/3): test_dir_item.rb'},
191
- {severity: 'DEBUG', task: 'ProcessFiles/ChecksumTester', message: 'Processing subitem (2/3): test_file_item.rb'},
192
- {severity: 'DEBUG', task: 'ProcessFiles/ChecksumTester', message: 'Processing subitem (3/3): test_run.rb'},
193
- {severity: 'DEBUG', task: 'ProcessFiles/ChecksumTester', message: '3 of 3 subitems passed'},
194
- {severity: 'DEBUG', task: 'ProcessFiles/CamelizeName', message: 'Processing subitem (1/3): test_dir_item.rb'},
195
- {severity: 'DEBUG', task: 'ProcessFiles/CamelizeName', message: 'Processing subitem (2/3): test_file_item.rb'},
196
- {severity: 'DEBUG', task: 'ProcessFiles/CamelizeName', message: 'Processing subitem (3/3): test_run.rb'},
197
- {severity: 'DEBUG', task: 'ProcessFiles/CamelizeName', message: '3 of 3 subitems passed'},
198
- ].each_with_index do |h, i|
199
- h.keys.each { |key| expect(run.items.first.log_history[i][key]).to eq h[key] }
200
- end
201
-
202
- # noinspection RubyResolve
203
- expect(run.items.first.first.log_history).to be_empty
204
-
205
153
  end
206
154
 
207
155
  end
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.12
4
+ version: 2.0.13
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kris Dekeyser
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-04-13 00:00:00.000000000 Z
11
+ date: 2016-04-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler