Class: BenefitsIntake::SubmissionStatusJob

Inherits:
Object
  • Object
show all
Includes:
Sidekiq::Job
Defined in:
lib/lighthouse/benefits_intake/sidekiq/submission_status_job.rb

Constant Summary collapse

STATS_KEY =
'api.benefits_intake.submission_status'
STALE_SLA =
Settings.lighthouse.benefits_intake.report.stale_sla || 10
BATCH_SIZE =
Settings.lighthouse.benefits_intake.report.batch_size || 1000
STATUS_RESULT_MAP =

any status not listed will result in ‘pending’

{
  expired: 'failure', # Indicates that documents were not successfully uploaded within the 15-minute window
  error: 'failure',   # Indicates that there was an error. Refer to the code and detail for further information
  vbms: 'success',    # Submission was successfully uploaded into a Veteran's eFolder within VBMS
  success: 'pending', # Submission was successfully received into Lighthouse systems
  pending: 'pending', # Submission is being processed
  stale: 'stale'      # Exceeds SLA (service level agreement) days for submission completion; non-lighthouse status
}.freeze
FORM_HANDLERS =

A hash mapping form IDs to their corresponding handlers. This constant is intentionally mutable.

See Also:

{}

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(batch_size: BATCH_SIZE) ⇒ SubmissionStatusJob

Returns a new instance of SubmissionStatusJob.



52
53
54
# File 'lib/lighthouse/benefits_intake/sidekiq/submission_status_job.rb', line 52

def initialize(batch_size: BATCH_SIZE)
  @batch_size = batch_size
end

Instance Attribute Details

#batch_sizeObject (readonly, private)

Returns the value of attribute batch_size.



71
72
73
# File 'lib/lighthouse/benefits_intake/sidekiq/submission_status_job.rb', line 71

def batch_size
  @batch_size
end

#form_idObject (readonly, private)

Returns the value of attribute form_id.



71
72
73
# File 'lib/lighthouse/benefits_intake/sidekiq/submission_status_job.rb', line 71

def form_id
  @form_id
end

Class Method Details

.register_handler(form_id, form_handler) ⇒ Object

Registers a form class with a specific form ID.

Parameters:

  • form_id (String)

    The form ID to register.

  • form_handler (Class)

    The class associated with the form ID.



39
40
41
# File 'lib/lighthouse/benefits_intake/sidekiq/submission_status_job.rb', line 39

def self.register_handler(form_id, form_handler)
  FORM_HANDLERS[form_id] = form_handler
end

Instance Method Details

#attempt_status_result(uuid, status) ⇒ Object (private)



177
178
179
180
181
182
183
184
185
# File 'lib/lighthouse/benefits_intake/sidekiq/submission_status_job.rb', line 177

def attempt_status_result(uuid, status)
  form_submission_attempt = pending_attempts_hash[uuid]

  queue_time = (Time.zone.now - form_submission_attempt.created_at).truncate
  result = STATUS_RESULT_MAP[status.to_sym] || 'pending'
  result = 'stale' if queue_time > STALE_SLA.days && result == 'pending'

  [form_submission_attempt, result]
end

#batch_process(pending_attempts) ⇒ Object (private)



79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/lighthouse/benefits_intake/sidekiq/submission_status_job.rb', line 79

def batch_process(pending_attempts)
  intake_service = BenefitsIntake::Service.new

  pending_attempts.each_slice(batch_size) do |batch|
    batch_uuids = batch.map(&:benefits_intake_uuid)
    log(:info, 'processing batch', batch_uuids:)

    response = intake_service.bulk_status(uuids: batch_uuids)

    log(:info, 'bulk status response', response:)
    raise response.body unless response.success?

    next unless (data = response.body['data'])

    handle_response(data)
  end
rescue => e
  log(:error, 'ERROR processing batch', message: e.message)
end

#handle_attempt_result(uuid, status) ⇒ Object (private)



166
167
168
169
170
171
172
173
174
175
# File 'lib/lighthouse/benefits_intake/sidekiq/submission_status_job.rb', line 166

def handle_attempt_result(uuid, status)
  form_submission_attempt, result = attempt_status_result(uuid, status)
  saved_claim_id = form_submission_attempt.form_submission.saved_claim_id

  call_location = caller_locations.first
  context = { benefits_intake_uuid: uuid }
  FORM_HANDLERS[form_id]&.new(saved_claim_id)&.handle(result, call_location:, **context)
rescue => e
  log(:error, 'ERROR handling result', message: e.message)
end

#handle_response(response_data) ⇒ Object (private)



105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
# File 'lib/lighthouse/benefits_intake/sidekiq/submission_status_job.rb', line 105

def handle_response(response_data)
  response_data.each do |submission|
    uuid = submission['id']

    next unless pending_attempts_hash[uuid]

    # Log the status for debugging
    status = submission.dig('attributes', 'status')
    log(:info, "Processing submission UUID: #{uuid}, Status: #{status}")

    update_attempt_record(uuid, status, submission)
    monitor_attempt_status(uuid, status)

    handle_attempt_result(uuid, status)
  end
end

#log(level, msg, **payload) ⇒ Object (private)



73
74
75
76
77
# File 'lib/lighthouse/benefits_intake/sidekiq/submission_status_job.rb', line 73

def log(level, msg, **payload)
  this = self.class.name
  message = format('%<class>s: %<msg>s', { class: this, msg: msg.to_s })
  Rails.logger.public_send(level, message, class: this, **payload)
end

#monitor_attempt_status(uuid, status) ⇒ Object (private)



145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
# File 'lib/lighthouse/benefits_intake/sidekiq/submission_status_job.rb', line 145

def monitor_attempt_status(uuid, status)
  form_submission_attempt, result = attempt_status_result(uuid, status)
  form_id = form_submission_attempt.form_submission.form_type

  metric = "#{STATS_KEY}.#{form_id}.#{result}"
  StatsD.increment(metric)
  StatsD.increment("#{STATS_KEY}.all_forms.#{result}")

  level = result == 'failure' ? :error : :info
  payload = {
    statsd: metric,
    form_id:,
    uuid:,
    result:,
    status:,
    time_to_transition: (Time.zone.now - form_submission_attempt.created_at).truncate,
    error_message: form_submission_attempt.error_message
  }
  log(level, "UUID: #{uuid}, status: #{status}, result: #{result}", **payload)
end

#pending_attempts_hashObject (private)



99
100
101
102
# File 'lib/lighthouse/benefits_intake/sidekiq/submission_status_job.rb', line 99

def pending_attempts_hash
  @pah ||= FormSubmissionAttempt.where(aasm_state: 'pending').includes(:form_submission)
                                .index_by(&:benefits_intake_uuid)
end

#perform(form_id = nil) ⇒ Object



56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/lighthouse/benefits_intake/sidekiq/submission_status_job.rb', line 56

def perform(form_id = nil)
  log(:info, 'started')

  pending_attempts = FormSubmissionAttempt.where(aasm_state: 'pending').includes(:form_submission)

  # filter running this job to a specific form_id/form_type
  pending_attempts.select! { |pa| pa.form_submission.form_type == form_id } if form_id

  batch_process(pending_attempts) unless pending_attempts.empty?

  log(:info, 'ended')
end

#update_attempt_record(uuid, status, submission) ⇒ Object (private)



122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/lighthouse/benefits_intake/sidekiq/submission_status_job.rb', line 122

def update_attempt_record(uuid, status, submission)
  form_submission_attempt = pending_attempts_hash[uuid]
  lighthouse_updated_at = submission.dig('attributes', 'updated_at')

  case status
  when 'expired'
    # Indicates that documents were not successfully uploaded within the 15-minute window.
    error_message = 'expired'
    form_submission_attempt.fail!

  when 'error'
    # Indicates that there was an error. Refer to the error code and detail for further information.
    error_message = "#{submission.dig('attributes', 'code')}: #{submission.dig('attributes', 'detail')}"
    form_submission_attempt.fail!

  when 'vbms'
    # Submission was successfully uploaded into a Veteran's eFolder within VBMS
    form_submission_attempt.vbms!
  end

  form_submission_attempt.update(lighthouse_updated_at:, error_message:)
end