correctif(procedure.declarative): ETQ administrateur d'une procedure declarative, certains de mes dossiers restent en construction [ex: l'object storage est down, le dossier reste bloqué]

This commit is contained in:
Martin 2023-04-21 11:40:23 +02:00
parent 88f680a265
commit 9dec6f1611
3 changed files with 157 additions and 0 deletions

View file

@ -0,0 +1,14 @@
class Cron::StalledDeclarativeProceduresJob < Cron::CronJob
self.schedule_expression = "every 10 minute"
def perform(*args)
Procedure.declarative.find_each do |procedure|
begin
procedure.process_stalled_dossiers!
rescue => e
Sentry.set_tags(procedure: procedure.id)
Sentry.capture_exception(e)
end
end
end
end

View file

@ -479,6 +479,23 @@ class Procedure < ApplicationRecord
end end
end end
def process_stalled_dossiers!
case declarative_with_state
when Procedure.declarative_with_states.fetch(:en_instruction)
dossiers
.state_en_construction
.where(declarative_triggered_at: nil)
.find_each(&:passer_automatiquement_en_instruction!)
when Procedure.declarative_with_states.fetch(:accepte)
dossiers
.state_en_construction
.where(declarative_triggered_at: nil)
.find_each do |dossier|
dossier.accepter_automatiquement! if dossier.can_accepter_automatiquement?
end
end
end
def feature_enabled?(feature) def feature_enabled?(feature)
Flipper.enabled?(feature, self) Flipper.enabled?(feature, self)
end end

View file

@ -0,0 +1,126 @@
RSpec.describe Cron::StalledDeclarativeProceduresJob, type: :job do
describe "perform" do
let(:date) { Time.utc(2017, 9, 1, 10, 5, 0) }
let(:instruction_date) { date + 120 }
let(:state) { nil }
let(:procedure) { create(:procedure, :published, :for_individual, :with_instructeur, declarative_with_state: state) }
let(:nouveau_dossier1) { create(:dossier, :en_construction, :with_individual, :with_attestation, procedure: procedure) }
let(:nouveau_dossier2) { create(:dossier, :en_construction, :with_individual, :with_attestation, procedure: procedure) }
let(:dossier_recu) { create(:dossier, :en_instruction, :with_individual, procedure: procedure) }
let(:dossier_brouillon) { create(:dossier, procedure: procedure) }
let(:dossier_repasse_en_construction) { create(:dossier, :en_construction, :with_individual, procedure: procedure) }
before do
Timecop.freeze(date)
dossier_repasse_en_construction&.touch(:declarative_triggered_at)
end
subject(:perform_job) do
dossiers = [
nouveau_dossier1,
nouveau_dossier2,
dossier_recu,
dossier_brouillon,
dossier_repasse_en_construction
].compact
Cron::StalledDeclarativeProceduresJob.new.perform
dossiers.each(&:reload)
end
after { Timecop.return }
context "with some dossiers" do
context "en_construction" do
let(:state) { Dossier.states.fetch(:en_instruction) }
let(:last_operation) { nouveau_dossier1.dossier_operation_logs.last }
it {
perform_job
expect(nouveau_dossier1.en_instruction?).to be_truthy
expect(nouveau_dossier1.en_instruction_at).to eq(date)
expect(last_operation.operation).to eq('passer_en_instruction')
expect(last_operation.automatic_operation?).to be_truthy
expect(nouveau_dossier2.en_instruction?).to be_truthy
expect(nouveau_dossier2.en_instruction_at).to eq(date)
expect(dossier_recu.en_instruction?).to be_truthy
expect(dossier_recu.en_instruction_at).to eq(instruction_date)
expect(dossier_brouillon.brouillon?).to be_truthy
expect(dossier_brouillon.en_instruction_at).to eq(nil)
expect(dossier_repasse_en_construction.en_construction?).to be_truthy
}
end
context "accepte" do
let(:state) { Dossier.states.fetch(:accepte) }
let(:last_operation) { nouveau_dossier1.dossier_operation_logs.last }
it {
perform_job
expect(nouveau_dossier1.accepte?).to be true
expect(nouveau_dossier1.en_instruction_at).to eq(date)
expect(nouveau_dossier1.processed_at).to eq(date)
expect(nouveau_dossier1.attestation).to be_present
expect(last_operation.operation).to eq('accepter')
expect(last_operation.automatic_operation?).to be_truthy
expect(nouveau_dossier2.accepte?).to be true
expect(nouveau_dossier2.en_instruction_at).to eq(date)
expect(nouveau_dossier2.processed_at).to eq(date)
expect(nouveau_dossier2.attestation).to be_present
expect(dossier_recu.en_instruction?).to be true
expect(dossier_recu.en_instruction_at).to eq(instruction_date)
expect(dossier_recu.processed_at).to eq(nil)
expect(dossier_brouillon.brouillon?).to be true
expect(dossier_brouillon.en_instruction_at).to eq(nil)
expect(dossier_brouillon.processed_at).to eq(nil)
}
context "having etablissement in degraded_mode" do
let(:procedure) { create(:procedure, :published, :with_instructeur, for_individual: false, declarative_with_state: state) }
let(:nouveau_dossier1) { create(:dossier, :en_construction, :with_entreprise, :with_attestation, procedure: procedure, as_degraded_mode: false) }
let(:nouveau_dossier2) { create(:dossier, :en_construction, :with_entreprise, :with_attestation, procedure: procedure, as_degraded_mode: true) }
let(:dossier_recu) { nil }
let(:dossier_repasse_en_construction) { nil }
before do
expect(nouveau_dossier2).to_not receive(:accepter_automatiquement!)
expect(Sentry).to_not receive(:capture_exception)
end
it {
perform_job
expect(nouveau_dossier1).to be_accepte
expect(nouveau_dossier2).to be_en_construction
}
end
end
end
end
describe 'safer perform' do
let(:state) { Dossier.states.fetch(:en_instruction) }
it 'works no matter if one raise' do
procedure_1 = instance_double("Procedure", id: 1)
expect(procedure_1).to receive(:process_stalled_dossiers!)
procedure_2 = instance_double("Procedure", id: 2)
expect(procedure_2).to receive(:process_stalled_dossiers!).and_raise("boom")
procedure_3 = double(process_stalled_dossiers!: true)
expect(procedure_3).to receive(:process_stalled_dossiers!)
expect(Procedure).to receive_message_chain(:declarative, :find_each).and_yield(procedure_1).and_yield(procedure_2).and_yield(procedure_3)
Cron::StalledDeclarativeProceduresJob.perform_now
end
end
end