lyber-core 4.1.3 → 4.1.4

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: b4fb7e891b91c5c229147d0c56c5c6e4ee98e4b1
4
- data.tar.gz: 2cd2447a9967a2f24a96ba8135bd50084a20cda1
3
+ metadata.gz: a1489790b66195312397f9325c4e61119086d903
4
+ data.tar.gz: e5db26df5720035e46f22360246f680dfbe87b10
5
5
  SHA512:
6
- metadata.gz: b358e476ab7fa8726a87b4ea0ac945e2e18823273990c78aac31f91585a46b47004687f0362f72c430ebb1f7cdcfb860147dda8a056a6d0073eb2a25ece0efb3
7
- data.tar.gz: 2189c3ca99c2e16ef0bb634cb4d6aee9d346ba2883e78c5c3da5d6cfee6c1080ea4dd1721957a3da8d0b215848d1c9a6362a046fc0221cb2f327c6136e7a7f63
6
+ metadata.gz: 5af41b19bb03d42890596fe374187cbc856d768fedff25b104522b2717a08adc2dff41d5c826455284cd89a7d761906ecb57633c8a0d2419ebd9616f7ab9ce2f
7
+ data.tar.gz: 0647f4d26c22e049c59bbc814f1dafc5463169e2e0ee687a77d9b0e4051d37ac9015280f7e2bc0fa967a6b47e2a315adaf4fd418adcdc6b712562ff7149fba09
@@ -1,3 +1,6 @@
1
+ require 'dor-workflow-service'
2
+
3
+ require 'lyber_core/base'
1
4
  require 'lyber_core/log'
2
5
  require 'lyber_core/robot'
3
6
  require 'lyber_core/return_state'
@@ -0,0 +1,91 @@
1
+ require 'benchmark'
2
+ require 'active_support'
3
+
4
+ module LyberCore
5
+ # The skeleton of robots, a replacement for LyberCore::Robot
6
+ # @example To migrate from LyberCore::Robot, replace
7
+ # class MyRobot
8
+ # include LyberCore::Robot
9
+ # def initialize
10
+ # new(REPOSITORY, WORKFLOW_NAME, ROBOT_NAME)
11
+ # end
12
+ # def perform ...
13
+ # end
14
+ # @example Usage: implement self.worker and override #perform, as before
15
+ # class MyRobot < LyberCore::Base
16
+ # def self.worker
17
+ # new('sdr', 'preservationIngestWF', 'ingest-poison')
18
+ # end
19
+ # def perform ...
20
+ # end
21
+ class Base
22
+ # Called by job-manager: instantiate the Robot and call #work with the druid
23
+ # @param [String] druid
24
+ # @note Override the instance method #perform, probably not this one
25
+ def self.perform(druid)
26
+ worker.work(druid)
27
+ end
28
+
29
+ # get an instance, without knowing the params for .new()
30
+ # @return [LyberCore::Base]
31
+ def self.worker
32
+ raise NotImplementedError, 'Implement class method self.worker on the subclass'
33
+ end
34
+
35
+ attr_accessor :repo, :workflow_name, :step_name, :check_queued_status, :workflow_service
36
+
37
+ def initialize(repo, workflow_name, step_name, opts = {})
38
+ Signal.trap('QUIT') { puts "#{Process.pid} ignoring SIGQUIT" } # SIGQUIT ignored to let the robot finish
39
+ @repo = repo
40
+ @workflow_name = workflow_name
41
+ @step_name = step_name
42
+ @check_queued_status = opts.fetch(:check_queued_status, true)
43
+ @workflow_service = opts.fetch(:workflow_service, Dor::WorkflowService)
44
+ end
45
+
46
+ # @return [Logger]
47
+ def logger
48
+ unless @log_init # one time
49
+ LyberCore::Log.set_logfile($stdout) # let process manager(bluepill) handle logging
50
+ @log_init = true
51
+ end
52
+ LyberCore::Log
53
+ end
54
+
55
+ # Sets up logging, timing and error handling of the job
56
+ # Calls the #perform method, then sets workflow to 'completed' or 'error' depending on success
57
+ def work(druid)
58
+ logger.info "#{druid} processing"
59
+ return if check_queued_status && !item_queued?(druid)
60
+ result = nil
61
+ elapsed = Benchmark.realtime { result = perform(druid) }
62
+ if result.is_a?(LyberCore::Robot::ReturnState)
63
+ workflow_state = result.status
64
+ note = result.note unless result.note.blank?
65
+ else
66
+ workflow_state = 'completed' # default
67
+ end
68
+ note ||= Socket.gethostname # default
69
+ workflow_service.update_workflow_status(repo, druid, workflow_name, step_name, workflow_state, elapsed: elapsed, note: note)
70
+ logger.info "Finished #{druid} in #{format('%0.4f', elapsed)}s"
71
+ rescue StandardError => e
72
+ Honeybadger.notify(e) if defined? Honeybadger
73
+ begin
74
+ logger.error e.message + "\n" + e.backtrace.join("\n")
75
+ workflow_service.update_workflow_error_status(repo, druid, workflow_name, step_name, e.message, error_text: Socket.gethostname)
76
+ rescue StandardError => e2
77
+ logger.error "Cannot set #{druid} to status='error'\n" + e2.message + "\n" + e2.backtrace.join("\n")
78
+ raise e2 # send exception to Resque failed queue
79
+ end
80
+ end
81
+
82
+ private
83
+
84
+ def item_queued?(druid)
85
+ status = workflow_service.get_workflow_status(repo, druid, workflow_name, step_name)
86
+ return true if status =~ /queued/i
87
+ logger.warn "Item is not queued, but has status of '#{status}'. Will skip processing"
88
+ false
89
+ end
90
+ end
91
+ end
@@ -1,14 +1,13 @@
1
-
2
1
  module LyberCore
3
-
4
2
  class LyberCore::Log
5
3
  require 'logger'
6
4
 
7
5
  # Default values
8
- DEFAULT_LOGFILE = "/tmp/lybercore_log.log" # TODO change to STDOUT?
6
+ DEFAULT_LOGFILE = '/tmp/lybercore_log.log'.freeze # TODO change to STDOUT?
9
7
  DEFAULT_LOG_LEVEL = Logger::INFO
10
- DEFAULT_FORMATTER = proc{|s,t,p,m|"%5s [%s] (%s) %s :: %s\n" % [s,
11
- t.strftime("%Y-%m-%d %H:%M:%S"), $$, p, m]}
8
+ DEFAULT_FORMATTER = proc do |s, t, p, m|
9
+ "%5s [%s] (%s) %s :: %s\n" % [s, t.strftime('%Y-%m-%d %H:%M:%S'), $$, p, m]
10
+ end
12
11
 
13
12
  # Initial state
14
13
  @@logfile = DEFAULT_LOGFILE
@@ -27,27 +26,22 @@ module LyberCore
27
26
 
28
27
  # The current location of the logfile
29
28
  def Log.logfile
30
- return @@logfile
29
+ @@logfile
31
30
  end
32
31
 
33
-
34
-
35
32
  # Accepts a filename as an argument, and checks to see whether that file can be
36
33
  # opened for writing. If it can be opened, it closes the existing Logger object
37
34
  # and re-opens it with the new logfile location. It raises an exception if it
38
35
  # cannot write to the specified logfile.
39
36
  def Log.set_logfile(new_logfile)
40
- begin
41
- current_log_level = @@log.level
42
- current_formatter = @@log.formatter
43
- @@log = Logger.new(new_logfile)
44
- @@logfile = new_logfile
45
- @@log.level = current_log_level
46
- @@log.formatter = current_formatter
47
- rescue Exception => e
48
- raise e, "Couldn't initialize logfile #{new_logfile} because\n#{e.message}: #{e.backtrace.join(%{\n})}}"
49
- end
50
-
37
+ current_log_level = @@log.level
38
+ current_formatter = @@log.formatter
39
+ @@log = Logger.new(new_logfile)
40
+ @@logfile = new_logfile
41
+ @@log.level = current_log_level
42
+ @@log.formatter = current_formatter
43
+ rescue Exception => e
44
+ raise e, "Couldn't initialize logfile #{new_logfile} because\n#{e.message}: #{e.backtrace.join(%(\n))}}"
51
45
  end
52
46
 
53
47
  # Set the log level.
@@ -59,18 +53,16 @@ module LyberCore
59
53
  # Logger::INFO (1): generic (useful) information about system operation
60
54
  # Logger::DEBUG (0): low-level information for developers
61
55
  def Log.set_level(loglevel)
62
- begin
63
- if [0,1,2,3,4].include? loglevel
64
- @@log.level = loglevel
65
- @@log.debug "Setting LyberCore::Log.level to #{loglevel}"
66
- else
67
- @@log.warn "I received an invalid option for log level. I expected a number between 0 and 4 but I got #{loglevel}"
68
- @@log.warn "I'm setting the loglevel to 0 (debug) because you seem to be having trouble."
69
- @@log.level = 0
70
- end
71
- rescue Exception => e
72
- raise e, "Couldn't set log level because\n#{e.message}: #{e.backtrace.join(%{\n})}"
56
+ if [0, 1, 2, 3, 4].include? loglevel
57
+ @@log.level = loglevel
58
+ @@log.debug "Setting LyberCore::Log.level to #{loglevel}"
59
+ else
60
+ @@log.warn "I received an invalid option for log level. I expected a number between 0 and 4 but I got #{loglevel}"
61
+ @@log.warn "I'm setting the loglevel to 0 (debug) because you seem to be having trouble."
62
+ @@log.level = 0
73
63
  end
64
+ rescue Exception => e
65
+ raise e, "Couldn't set log level because\n#{e.message}: #{e.backtrace.join(%(\n))}"
74
66
  end
75
67
 
76
68
  # Return the current log level
@@ -105,10 +97,7 @@ module LyberCore
105
97
 
106
98
  def Log.exception_message(e)
107
99
  msg = e.inspect.split($/).join('; ') + "\n"
108
- msg << e.backtrace.join("\n") if(e.backtrace)
100
+ msg << e.backtrace.join("\n") if e.backtrace
109
101
  end
110
-
111
102
  end
112
-
113
-
114
- end
103
+ end
@@ -1,38 +1,36 @@
1
1
  # this object defines the allowed states robots can optionally return upon completion
2
- # if the return value of the "perform" step is an object of this type and the status value is set an allowed value,
2
+ # if the return value of the "perform" step is an object of this type and the status value is set an allowed value,
3
3
  # it will be used to set the final workflow state for that druid
4
4
  module LyberCore
5
5
  module Robot
6
6
  class ReturnState
7
-
8
7
  attr_reader :status
9
8
  attr_accessor :note
10
- ALLOWED_RETURN_STATES = %w{completed skipped waiting}
11
- DEFAULT_RETURN_STATE = 'completed'
12
-
9
+ ALLOWED_RETURN_STATES = %w[completed skipped waiting].freeze
10
+ DEFAULT_RETURN_STATE = 'completed'.freeze
11
+
13
12
  def self.SKIPPED
14
- self.new(status: 'skipped')
13
+ new(status: 'skipped')
15
14
  end
16
15
 
17
16
  def self.COMPLETED
18
- self.new(status: 'completed')
17
+ new(status: 'completed')
19
18
  end
20
19
 
21
20
  def self.WAITING
22
- self.new(status: 'waiting')
21
+ new(status: 'waiting')
23
22
  end
24
23
 
25
24
  def initialize(params = {})
26
25
  self.status = params[:status] || DEFAULT_RETURN_STATE
27
- self.note = params[:note] || ""
26
+ self.note = params[:note] || ''
28
27
  end
29
-
28
+
30
29
  def status=(value)
31
30
  state = value.to_s.downcase
32
31
  raise 'invalid return state' unless ALLOWED_RETURN_STATES.include? state
33
32
  @status = state
34
33
  end
35
-
36
34
  end
37
35
  end
38
36
  end
@@ -5,25 +5,20 @@ require 'active_support/core_ext/string/inflections' # camelcase
5
5
 
6
6
  module LyberCore
7
7
  module Robot
8
-
9
8
  # Add the ClassMethods to the class this is being mixed into
10
- def self.included base
9
+ def self.included(base)
11
10
  base.extend ClassMethods
12
11
  end
13
12
 
14
13
  module ClassMethods
15
-
16
14
  # Called by job-manager on derived-class
17
15
  # Instantiate the Robot and call #work with the passed in druid
18
16
  def perform(druid)
19
- # Get the name of the derived-class that was invoked
20
- klazz = self.name.split('::').inject(Object) {|o,c| o.const_get c}
21
- bot = klazz.new
17
+ bot = new
22
18
  bot.work druid
23
19
  end
24
20
  end
25
21
 
26
-
27
22
  # Converts a given step to the Robot class name
28
23
  # Examples:
29
24
  #
@@ -35,15 +30,15 @@ module LyberCore
35
30
  # @param [Hash] opts
36
31
  # @option :repo_suffix defaults to `Repo`
37
32
  # @return [String] The class name for the robot, e.g., `Robots::DorRepo::Accession:DescriptiveMetadata`
38
- def self.step_to_classname step, opts = {}
33
+ def self.step_to_classname(step, opts = {})
39
34
  # generate the robot job class name
40
35
  opts[:repo_suffix] ||= 'Repo'
41
36
  r, w, s = step.split(/:/, 3)
42
- return [
37
+ [
43
38
  'Robots',
44
39
  r.camelcase + opts[:repo_suffix], # 'Dor' conflicts with dor-services
45
40
  w.sub('WF', '').camelcase,
46
- s.gsub('-', '_').camelcase
41
+ s.tr('-', '_').camelcase
47
42
  ].join('::')
48
43
  end
49
44
 
@@ -51,7 +46,7 @@ module LyberCore
51
46
  attr_reader :workflow_service
52
47
 
53
48
  def initialize(repo, workflow_name, step_name, opts = {})
54
- Signal.trap("QUIT") { puts "#{Process.pid} ignoring SIGQUIT" } # SIGQUIT ignored to let the robot finish
49
+ Signal.trap('QUIT') { puts "#{Process.pid} ignoring SIGQUIT" } # SIGQUIT ignored to let the robot finish
55
50
  @repo = repo
56
51
  @workflow_name = workflow_name
57
52
  @step_name = step_name
@@ -62,54 +57,49 @@ module LyberCore
62
57
  # Sets up logging, timing and error handling of the job
63
58
  # Calls the #perform method, then sets workflow to 'completed' or 'error' depending on success
64
59
  def work(druid)
65
- LyberCore::Log.set_logfile($stdout) # let process manager(bluepill) handle logging
60
+ LyberCore::Log.set_logfile($stdout) # let process manager(bluepill) handle logging
66
61
  LyberCore::Log.info "#{druid} processing"
67
62
  return if @check_queued_status && !item_queued?(druid)
68
63
 
69
64
  result = nil
70
65
  elapsed = Benchmark.realtime do
71
- result = self.perform druid # implemented in the mixed-in robot class
66
+ result = perform druid # implemented in the mixed-in robot class
72
67
  end
73
68
 
74
69
  # this is the default note to pass back to workflow service, but it can be overriden by a robot that uses the Lybercore::Robot::ReturnState object to return a status
75
70
  note = Socket.gethostname
76
-
77
- # the final workflow state is determined by the return value of the perform step, if it is a ReturnState object,
71
+
72
+ # the final workflow state is determined by the return value of the perform step, if it is a ReturnState object,
78
73
  # we will use the defined status, otherwise default to completed
79
74
  # if a note is passed back, we will also use that instead of the default
80
75
  if result.class == LyberCore::Robot::ReturnState
81
76
  workflow_state = result.status
82
77
  note = result.note unless result.note.blank?
83
78
  else
84
- workflow_state = 'completed'
79
+ workflow_state = 'completed'
85
80
  end
86
-
87
- # update the workflow status from its current state to the state returned by perform (or 'completed' as the default)
88
- workflow_service.update_workflow_status @repo, druid, @workflow_name, @step_name, workflow_state, :elapsed => elapsed, :note => note
89
- LyberCore::Log.info "Finished #{druid} in #{sprintf("%0.4f",elapsed)}s"
90
81
 
91
- rescue => e
82
+ # update the workflow status from its current state to the state returned by perform (or 'completed' as the default)
83
+ workflow_service.update_workflow_status(@repo, druid, @workflow_name, @step_name, workflow_state, elapsed: elapsed, note: note)
84
+ LyberCore::Log.info "Finished #{druid} in #{sprintf('%0.4f', elapsed)}s"
85
+ rescue StandardError => e
92
86
  Honeybadger.notify(e) if defined? Honeybadger
93
87
  begin
94
88
  LyberCore::Log.error e.message + "\n" + e.backtrace.join("\n")
95
- workflow_service.update_workflow_error_status @repo, druid , @workflow_name, @step_name, e.message, :error_text => Socket.gethostname
96
- rescue => e2
89
+ workflow_service.update_workflow_error_status(@repo, druid, @workflow_name, @step_name, e.message, error_text: Socket.gethostname)
90
+ rescue StandardError => e2
97
91
  LyberCore::Log.error "Cannot set #{druid} to status='error'\n" + e2.message + "\n" + e2.backtrace.join("\n")
98
92
  raise e2 # send exception to Resque failed queue
99
93
  end
100
94
  end
101
95
 
102
- private
96
+ private
103
97
 
104
98
  def item_queued?(druid)
105
99
  status = workflow_service.get_workflow_status(@repo, druid, @workflow_name, @step_name)
106
- if(status =~ /queued/i)
107
- return true
108
- else
109
- LyberCore::Log.warn "Item is not queued, but has status of '#{status}'. Will skip processing"
110
- return false
111
- end
100
+ return true if status =~ /queued/i
101
+ LyberCore::Log.warn "Item is not queued, but has status of '#{status}'. Will skip processing"
102
+ false
112
103
  end
113
-
114
104
  end
115
105
  end
@@ -1,5 +1,5 @@
1
- desc "Generate RDoc"
2
- task :doc => ['doc:generate']
1
+ desc 'Generate RDoc'
2
+ task doc: ['doc:generate']
3
3
 
4
4
  namespace :doc do
5
5
  project_root = File.expand_path(File.join(File.dirname(__FILE__), '..', '..'))
@@ -10,23 +10,22 @@ namespace :doc do
10
10
  require 'yard/rake/yardoc_task'
11
11
 
12
12
  YARD::Rake::YardocTask.new(:generate) do |yt|
13
- yt.files = Dir.glob(File.join(project_root, 'lib', '*.rb')) +
13
+ yt.files = Dir.glob(File.join(project_root, 'lib', '*.rb')) +
14
14
  Dir.glob(File.join(project_root, 'lib', '**', '*.rb')) +
15
- [ File.join(project_root, 'README.rdoc') ] +
16
- [ File.join(project_root, 'LICENSE') ]
17
-
15
+ [File.join(project_root, 'README.rdoc')] +
16
+ [File.join(project_root, 'LICENSE')]
17
+
18
18
  yt.options = ['--output-dir', doc_destination, '--readme', 'README.rdoc']
19
19
  end
20
20
  rescue LoadError
21
- desc "Generate YARD Documentation"
21
+ desc 'Generate YARD Documentation'
22
22
  task :generate do
23
- abort "Please install the YARD gem to generate rdoc."
23
+ abort 'Please install the YARD gem to generate rdoc.'
24
24
  end
25
25
  end
26
26
 
27
- desc "Remove generated documenation"
27
+ desc 'Remove generated documenation'
28
28
  task :clean do
29
- rm_r doc_destination if File.exists?(doc_destination)
29
+ rm_r doc_destination if File.exist?(doc_destination)
30
30
  end
31
-
32
- end
31
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lyber-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.1.3
4
+ version: 4.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alpana Pande
@@ -16,8 +16,22 @@ authors:
16
16
  autorequire:
17
17
  bindir: bin
18
18
  cert_chain: []
19
- date: 2017-07-17 00:00:00.000000000 Z
19
+ date: 2018-04-16 00:00:00.000000000 Z
20
20
  dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: activesupport
23
+ requirement: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ version: '0'
28
+ type: :runtime
29
+ prerelease: false
30
+ version_requirements: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
21
35
  - !ruby/object:Gem::Dependency
22
36
  name: dor-workflow-service
23
37
  requirement: !ruby/object:Gem::Requirement
@@ -39,13 +53,13 @@ dependencies:
39
53
  - !ruby/object:Gem::Version
40
54
  version: '3'
41
55
  - !ruby/object:Gem::Dependency
42
- name: activesupport
56
+ name: coveralls
43
57
  requirement: !ruby/object:Gem::Requirement
44
58
  requirements:
45
59
  - - ">="
46
60
  - !ruby/object:Gem::Version
47
61
  version: '0'
48
- type: :runtime
62
+ type: :development
49
63
  prerelease: false
50
64
  version_requirements: !ruby/object:Gem::Requirement
51
65
  requirements:
@@ -95,7 +109,7 @@ dependencies:
95
109
  - !ruby/object:Gem::Version
96
110
  version: '3.0'
97
111
  - !ruby/object:Gem::Dependency
98
- name: yard
112
+ name: rubocop
99
113
  requirement: !ruby/object:Gem::Requirement
100
114
  requirements:
101
115
  - - ">="
@@ -109,7 +123,21 @@ dependencies:
109
123
  - !ruby/object:Gem::Version
110
124
  version: '0'
111
125
  - !ruby/object:Gem::Dependency
112
- name: coveralls
126
+ name: rubocop-rspec
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '1.24'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '1.24'
139
+ - !ruby/object:Gem::Dependency
140
+ name: yard
113
141
  requirement: !ruby/object:Gem::Requirement
114
142
  requirements:
115
143
  - - ">="
@@ -134,6 +162,7 @@ files:
134
162
  - LICENSE
135
163
  - README.md
136
164
  - lib/lyber_core.rb
165
+ - lib/lyber_core/base.rb
137
166
  - lib/lyber_core/log.rb
138
167
  - lib/lyber_core/return_state.rb
139
168
  - lib/lyber_core/robot.rb
@@ -158,8 +187,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
158
187
  version: 1.3.6
159
188
  requirements: []
160
189
  rubyforge_project:
161
- rubygems_version: 2.6.12
190
+ rubygems_version: 2.6.11
162
191
  signing_key:
163
192
  specification_version: 4
164
193
  summary: Core services used by the SUL Digital Library
165
194
  test_files: []
195
+ has_rdoc: