You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
docuseal/lib/submissions/ensure_result_generated.rb

97 lines
3.2 KiB

# frozen_string_literal: true
module Submissions
module EnsureResultGenerated
WAIT_FOR_RETRY = 2.seconds
CHECK_EVENT_INTERVAL = 1.second
CHECK_COMPLETE_TIMEOUT = 90.seconds
WaitForCompleteTimeout = Class.new(StandardError)
NotCompletedYet = Class.new(StandardError)
module_function
def call(submitter)
return [] unless submitter
raise NotCompletedYet unless submitter.completed_at?
last_complete_event = ApplicationRecord.uncached do
submitter.document_generation_events.complete.order(:created_at).last
end
# Only return existing docs if they were generated AFTER the current completion
# This handles re-completion after change requests by comparing timestamps
if last_complete_event && last_complete_event.created_at >= submitter.completed_at
return latest_documents_for_event(submitter)
end
events =
ApplicationRecord.uncached do
DocumentGenerationEvent.where(submitter:).order(:created_at).to_a
end
last_event = events.last
# Check if last event is start/retry AND was created after current completion
# This means generation is actually in progress for THIS completion
is_generation_in_progress = last_event&.event_name&.in?(%w[start retry]) &&
last_event.created_at >= submitter.completed_at
if is_generation_in_progress
wait_for_complete_or_fail(submitter)
else
generate_and_record_documents(submitter, events)
end
rescue ActiveRecord::RecordNotUnique
sleep WAIT_FOR_RETRY
retry
rescue StandardError => e
Rollbar.error(e) if defined?(Rollbar)
submitter.document_generation_events.create!(event_name: :fail)
raise
end
def wait_for_complete_or_fail(submitter)
total_wait_time = 0
loop do
sleep CHECK_EVENT_INTERVAL
total_wait_time += CHECK_EVENT_INTERVAL
last_event =
ApplicationRecord.uncached do
DocumentGenerationEvent.where(submitter:).order(:created_at).last
end
break submitter.documents.reload if last_event.event_name.in?(%w[complete fail])
raise WaitForCompleteTimeout if total_wait_time > CHECK_COMPLETE_TIMEOUT
end
end
def latest_documents_for_event(submitter)
# Return documents created after the current completion timestamp
# This ensures we get the most recent generation, not old ones from previous completions
submitter.documents.where(active_storage_attachments: { created_at: submitter.completed_at.. })
end
def generate_and_record_documents(submitter, events)
submitter.document_generation_events.create!(event_name: events.present? ? :retry : :start)
documents = GenerateResultAttachments.call(submitter)
# Only create "complete" event if one doesn't exist for this completion
# Check if there's a complete event created AFTER this completion
unless submitter.document_generation_events.complete.exists?(created_at: submitter.completed_at..)
submitter.document_generation_events.create!(event_name: :complete)
end
documents
end
end
end