fix(api_entreprise): better handle api entreprise errors

This commit is contained in:
Paul Chavard 2024-10-14 15:58:32 +02:00
parent c8f69283cc
commit d13c475170
No known key found for this signature in database
7 changed files with 48 additions and 14 deletions

View file

@ -188,8 +188,8 @@ module Users
sanitized_siret = siret_model.siret
etablissement = begin
APIEntrepriseService.create_etablissement(@dossier, sanitized_siret, current_user.id)
rescue => error
if error.is_a?(APIEntreprise::API::Error::ServiceUnavailable) || (error.try(:network_error?) && !APIEntrepriseService.api_insee_up?)
rescue APIEntreprise::API::Error, APIEntrepriseToken::TokenError => error
if APIEntrepriseService.service_unavailable_error?(error, target: :insee)
# TODO: notify ops
APIEntrepriseService.create_etablissement_as_degraded_mode(@dossier, sanitized_siret, current_user.id)
else

View file

@ -0,0 +1,8 @@
# frozen_string_literal: true
class APIEntreprise::EtablissementJob < APIEntreprise::Job
def perform(etablissement_id, procedure_id)
find_etablissement(etablissement_id)
APIEntrepriseService.update_etablissement_from_degraded_mode(etablissement, procedure_id)
end
end

View file

@ -1,5 +1,6 @@
# frozen_string_literal: true
# TODO: remove this job in a few days once all failed etablissements are queued as separate jobs
class Cron::BackfillSiretDegradedModeJob < Cron::CronJob
self.schedule_expression = "every 2 hour"

View file

@ -138,10 +138,10 @@ class APIEntreprise::API
end
end
SERVICE_UNAVAILABLE_ERRORS = ["01000", "01001", "01002", "02002", "03002", "28002", "29002", "31002", "34002"]
def service_unavailable?(response)
return true if response.code == 503
if response.code == 502 || response.code == 504
parse_response_errors(response).any? { _1.is_a?(Hash) && ["01000", "01001", "01002", "02002", "03002"].include?(_1[:code]) }
parse_response_errors(response).any? { _1.is_a?(Hash) && _1[:code]&.in?(SERVICE_UNAVAILABLE_ERRORS) }
end
end

View file

@ -12,10 +12,14 @@ module RNAChampAssociationFetchableConcern
return clear_association!(:invalid) unless valid_champ_value?
return clear_association!(:not_found) if (data = APIEntreprise::RNAAdapter.new(rna, procedure_id).to_params).blank?
update!(data: data, value_json: APIGeoService.parse_rna_address(data['adresse']))
rescue APIEntreprise::API::Error => error
error_key = :network_error if error.try(:network_error?) && !APIEntrepriseService.api_djepva_up?
clear_association!(error_key)
update!(data:, value_json: APIGeoService.parse_rna_address(data['adresse']))
rescue APIEntreprise::API::Error, APIEntrepriseToken::TokenError => error
if APIEntrepriseService.service_unavailable_error?(error, target: :djepva)
clear_association!(:network_error)
else
Sentry.capture_exception(error, extra: { dossier_id:, rna: })
clear_association!(nil)
end
end
private

View file

@ -11,16 +11,16 @@ module SiretChampEtablissementFetchableConcern
return clear_etablissement!(:invalid_checksum) if invalid_because?(siret, :checksum) # i18n-tasks-use t('errors.messages.invalid_siret_checksum')
return clear_etablissement!(:not_found) unless (etablissement = APIEntrepriseService.create_etablissement(self, siret, user&.id)) # i18n-tasks-use t('errors.messages.siret_not_found')
update!(etablissement: etablissement, value_json: APIGeoService.parse_etablissement_address(etablissement))
rescue => error
if error.try(:network_error?) && !APIEntrepriseService.api_insee_up?
update!(etablissement:)
rescue APIEntreprise::API::Error, APIEntrepriseToken::TokenError => error
if APIEntrepriseService.service_unavailable_error?(error, target: :insee)
update!(
etablissement: APIEntrepriseService.create_etablissement_as_degraded_mode(self, siret, user.id)
)
@etablissement_fetch_error_key = :api_entreprise_down
false
else
Sentry.capture_exception(error, extra: { dossier_id: dossier_id, siret: siret })
Sentry.capture_exception(error, extra: { dossier_id:, siret: })
clear_etablissement!(:network_error) # i18n-tasks-use t('errors.messages.siret_network_error')
end
end

View file

@ -23,6 +23,10 @@ class APIEntrepriseService
etablissement = dossier_or_champ.build_etablissement(etablissement_params)
etablissement.save!
if dossier_or_champ.is_a?(Champ)
dossier_or_champ.update!(value_json: APIGeoService.parse_etablissement_address(etablissement))
end
perform_later_fetch_jobs(etablissement, procedure_id, user_id)
etablissement
@ -45,15 +49,25 @@ class APIEntrepriseService
return nil if etablissement_params.empty?
etablissement.update!(etablissement_params)
if etablissement.champ.present?
etablissement.champ.update!(value_json: APIGeoService.parse_etablissement_address(etablissement))
end
etablissement
end
def perform_later_fetch_jobs(etablissement, procedure_id, user_id, wait: nil)
[
jobs = [
APIEntreprise::EntrepriseJob, APIEntreprise::ExtraitKbisJob, APIEntreprise::TvaJob,
APIEntreprise::AssociationJob, APIEntreprise::ExercicesJob,
APIEntreprise::EffectifsJob, APIEntreprise::EffectifsAnnuelsJob, APIEntreprise::AttestationSocialeJob,
APIEntreprise::BilansBdfJob
].each do |job|
]
if etablissement.as_degraded_mode?
jobs << APIEntreprise::EtablissementJob
end
jobs.each do |job|
job.set(wait:).perform_later(etablissement.id, procedure_id)
end
@ -69,6 +83,13 @@ class APIEntrepriseService
api_up?("https://entreprise.api.gouv.fr/ping/djepva/api-association")
end
def service_unavailable_error?(error, target:)
return false if !error.try(:network_error?)
return true if target == :insee && !APIEntrepriseService.api_insee_up?
return true if target == :djepva && !APIEntrepriseService.api_djepva_up?
error.is_a?(APIEntreprise::API::Error::ServiceUnavailable)
end
private
def api_up?(url)