lyber-core 4.1.3 → 4.1.4

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 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: