Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 39 additions & 1 deletion app/jobs/dspace_publication_results_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ class DspacePublicationResultsJob < ActiveJob::Base
MAX_MESSAGES = ENV.fetch('SQS_RESULT_MAX_MESSAGES', 10)
WAIT_TIME_SECONDS = ENV.fetch('SQS_RESULT_WAIT_TIME_SECONDS', 10)
IDLE_TIMEOUT = ENV.fetch('SQS_RESULT_IDLE_TIMEOUT', 0)
MAX_ERROR_FIELD_LENGTH = 500
MAX_TRACEBACK_LENGTH = 1000

queue_as :default

Expand Down Expand Up @@ -124,7 +126,7 @@ def update_publication_status(thesis, body, results, status)
when 'success'
update_handle(thesis, body, results)
when 'error'
error = body['DSpaceResponse']
error = format_dss_error(body)
thesis.publication_status = 'Publication error'
thesis.save
Rails.logger.info("Thesis #{thesis.id} updated to status #{thesis.publication_status}. Error from DSS: #{error}")
Expand All @@ -138,6 +140,42 @@ def update_publication_status(thesis, body, results, status)
end
end

def format_dss_error(body)
details = []
details << format_error_detail('ErrorInfo', body['ErrorInfo']) if body['ErrorInfo'].present?
details << format_error_detail('DSpaceResponse', body['DSpaceResponse']) if body['DSpaceResponse'].present?
details << format_error_detail('ExceptionMessage', body['ExceptionMessage']) if body['ExceptionMessage'].present?

traceback = format_traceback(body['ExceptionTraceback'])
details << format_error_detail('ExceptionTraceback', traceback, max_length: MAX_TRACEBACK_LENGTH) if traceback.present?

return 'No error details provided by DSS' if details.empty?

details.join(' | ')
end

def format_error_detail(label, value, max_length: MAX_ERROR_FIELD_LENGTH)
normalized = value.to_s.gsub(/\s+/, ' ').strip
if normalized.length > max_length
normalized = "#{normalized[0...max_length]}...(truncated)"
end

"#{label}: #{normalized}"
end

def format_traceback(traceback)
lines = if traceback.is_a?(Array)
traceback
elsif traceback.is_a?(String)
traceback.split(/\r?\n/)
else
[]
end

lines = lines.map { |line| line.to_s.strip }
lines.reject(&:blank?).first(5).join(' || ')
end

def poll_messages(queue_url, results)
# https://docs.aws.amazon.com/sdk-for-ruby/v3/developer-guide/sqs-example-poll-messages.html
# Poller retrieves messages until there are none left and deletes them as it goes
Expand Down
7 changes: 7 additions & 0 deletions test/jobs/dspace_publication_results_job_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,13 @@ def teardown
'validate checksums as no local files were attached to the record. This ' \
'requires staff to manually check the ETD record and DSpace record and take ' \
'appropriate action.'

# DSS error details are surfaced from error payload
dss_error = results[:errors].find { |e| e.include?('ErrorInfo: Stuff broke') }
assert_not_nil dss_error, 'Expected DSS error with "ErrorInfo: Stuff broke" to be surfaced in results[:errors]'
assert_includes dss_error, 'ErrorInfo: Stuff broke'
assert_includes dss_error, 'ExceptionMessage: 500 Server Error: Internal Server Error'
assert_includes dss_error, 'ExceptionTraceback: Full unformatted stack trace of the Exception'
end

test 'enqueues preservation submission prep job' do
Expand Down
Loading