From 2bc00aecd7d9195cf45533dd75c0acbf1b2d66ee Mon Sep 17 00:00:00 2001 From: jazairi <16103405+jazairi@users.noreply.github.com> Date: Thu, 26 Mar 2026 11:57:06 -0700 Subject: [PATCH 1/2] Improve publication logging Why these changes are being introduced: Our current logging doesn't capture much information. (It usually just says 'N/A'.) While DSpace errors are not useful, we should still probably try to capture what's there. Relevant ticket(s): N/A How this addresses that need: That adds some Copilot-suggested changes to enhance our logging in the DSpace publication results job. Side effects of this change: None. --- app/jobs/dspace_publication_results_job.rb | 40 ++++++++++++++++++- .../dspace_publication_results_job_test.rb | 7 ++++ 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/app/jobs/dspace_publication_results_job.rb b/app/jobs/dspace_publication_results_job.rb index d4dbee7f..9f106781 100644 --- a/app/jobs/dspace_publication_results_job.rb +++ b/app/jobs/dspace_publication_results_job.rb @@ -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 @@ -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}") @@ -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 diff --git a/test/jobs/dspace_publication_results_job_test.rb b/test/jobs/dspace_publication_results_job_test.rb index 2778e173..ea8a3647 100644 --- a/test/jobs/dspace_publication_results_job_test.rb +++ b/test/jobs/dspace_publication_results_job_test.rb @@ -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 From 1acfe69ceb5dd1db7e5f9abedc559bc82a83e69e Mon Sep 17 00:00:00 2001 From: jazairi <16103405+jazairi@users.noreply.github.com> Date: Fri, 27 Mar 2026 08:20:24 -0700 Subject: [PATCH 2/2] Attempt to clarify test changes --- .../dspace_publication_results_job_test.rb | 29 ++++++++++++++++--- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/test/jobs/dspace_publication_results_job_test.rb b/test/jobs/dspace_publication_results_job_test.rb index ea8a3647..27353d50 100644 --- a/test/jobs/dspace_publication_results_job_test.rb +++ b/test/jobs/dspace_publication_results_job_test.rb @@ -180,12 +180,33 @@ def teardown '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]' + end + + test 'DSS error fields are surfaced in results errors' do + Aws.config[:sqs] = { + stub_responses: { + receive_message: [ + { + messages: [ + { message_id: 'id1', receipt_handle: 'handle1', + body: '{"ResultType": "error", "ErrorInfo": "Stuff broke", "DSpaceResponse": "N/A", "ExceptionMessage": "500 Server Error: Internal Server Error", "ExceptionTraceback": "Traceback (most recent call last):\nFile submission.py, line 84, in submit\nrequests.exceptions.HTTPError: 500 Server Error"}', + message_attributes: { 'PackageID' => { string_value: "etd_#{@bad_thesis.id}", data_type: 'String' }, + 'SubmissionSource' => { string_value: 'ETD', data_type: 'String' } } } + ] + }, + { messages: [] } + ] + } + } + + results = DspacePublicationResultsJob.perform_now + + dss_error = results[:errors].find { |e| e.include?('ErrorInfo:') } + assert_not_nil dss_error, 'Expected DSS error details to be surfaced in results[:errors]' assert_includes dss_error, 'ErrorInfo: Stuff broke' + assert_includes dss_error, 'DSpaceResponse: N/A' assert_includes dss_error, 'ExceptionMessage: 500 Server Error: Internal Server Error' - assert_includes dss_error, 'ExceptionTraceback: Full unformatted stack trace of the Exception' + assert_includes dss_error, 'ExceptionTraceback: Traceback (most recent call last):' end test 'enqueues preservation submission prep job' do