Checkpoint: Correction du scheduler de remerciements pour éviter les envois multiples - la vérification des doublons est maintenant faite en base de données (table logsNotifications) au lieu de la mémoire, ce qui persiste entre les redémarrages du serveur

This commit is contained in:
Manus Sandbox
2025-12-15 16:20:33 -05:00
parent b0cecb65f6
commit 29b35fceaa

View File

@@ -1,5 +1,5 @@
import { getDb } from "./db"; import { getDb } from "./db";
import { sequences, inscriptions, apprenants, formations, datesFormation, formateurs, questionnaires, envoisQuestionnaires } from "../drizzle/schema"; import { sequences, inscriptions, apprenants, formations, datesFormation, formateurs, questionnaires, envoisQuestionnaires, logsNotifications } from "../drizzle/schema";
import { eq, and, lte, sql } from "drizzle-orm"; import { eq, and, lte, sql } from "drizzle-orm";
import { sendRemerciementPostFormation } from "./emailService"; import { sendRemerciementPostFormation } from "./emailService";
import { logNotification } from "./notificationLogsDb"; import { logNotification } from "./notificationLogsDb";
@@ -79,24 +79,31 @@ async function getOrCreateQuestionnaireLink(
} }
/** /**
* Table pour suivre les remerciements déjà envoyés * Vérifie si un remerciement a déjà été envoyé pour une inscription en vérifiant dans la base de données
*/ */
const remerciementsEnvoyes = new Map<string, Date>(); async function remerciementDejaEnvoye(apprenantId: number, sequenceId: number): Promise<boolean> {
const db = await getDb();
if (!db) return false;
/** try {
* Vérifie si un remerciement a déjà été envoyé pour une inscription const [existing] = await db
*/ .select({ id: logsNotifications.id })
function remerciementDejaEnvoye(inscriptionId: number, sequenceId: number): boolean { .from(logsNotifications)
const key = `${inscriptionId}-${sequenceId}`; .where(
return remerciementsEnvoyes.has(key); and(
} eq(logsNotifications.type, "remerciement"),
eq(logsNotifications.apprenantId, apprenantId),
eq(logsNotifications.sequenceId, sequenceId),
eq(logsNotifications.statut, "success")
)
)
.limit(1);
/** return !!existing;
* Marque un remerciement comme envoyé } catch (error) {
*/ console.error("[Remerciements] Erreur lors de la vérification du log:", error);
function marquerRemerciementEnvoye(inscriptionId: number, sequenceId: number): void { return false;
const key = `${inscriptionId}-${sequenceId}`; }
remerciementsEnvoyes.set(key, new Date());
} }
/** /**
@@ -179,8 +186,9 @@ async function processRemerciementSequence(
let errorsCount = 0; let errorsCount = 0;
for (const { inscription, apprenant } of inscriptionsConfirmees) { for (const { inscription, apprenant } of inscriptionsConfirmees) {
// Vérifier si le remerciement a déjà été envoyé // Vérifier si le remerciement a déjà été envoyé (vérification en base de données)
if (remerciementDejaEnvoye(inscription.id, sequence.id)) { const dejaEnvoye = await remerciementDejaEnvoye(apprenant.id, sequence.id);
if (dejaEnvoye) {
console.log(`[Remerciements] Remerciement déjà envoyé pour ${apprenant.email}`); console.log(`[Remerciements] Remerciement déjà envoyé pour ${apprenant.email}`);
continue; continue;
} }
@@ -200,7 +208,7 @@ async function processRemerciementSequence(
lienQuestionnaire: lienQuestionnaire || undefined, lienQuestionnaire: lienQuestionnaire || undefined,
}); });
// Logger la notification // Logger la notification (sert aussi de marqueur pour éviter les doublons)
await logNotification({ await logNotification({
type: "remerciement", type: "remerciement",
sequenceId: sequence.id, sequenceId: sequence.id,
@@ -211,7 +219,6 @@ async function processRemerciementSequence(
metadata: { lienQuestionnaire }, metadata: { lienQuestionnaire },
}); });
marquerRemerciementEnvoye(inscription.id, sequence.id);
envoyesCount++; envoyesCount++;
console.log(`[Remerciements] Email envoyé à ${apprenant.email}`); console.log(`[Remerciements] Email envoyé à ${apprenant.email}`);
} catch (error: any) { } catch (error: any) {
@@ -289,6 +296,13 @@ export async function envoyerRemerciementsSequence(sequenceId: number): Promise<
let failed = 0; let failed = 0;
for (const { inscription, apprenant } of inscriptionsConfirmees) { for (const { inscription, apprenant } of inscriptionsConfirmees) {
// Vérifier si le remerciement a déjà été envoyé
const dejaEnvoye = await remerciementDejaEnvoye(apprenant.id, sequenceId);
if (dejaEnvoye) {
console.log(`[Remerciements] Remerciement déjà envoyé pour ${apprenant.email}, ignoré`);
continue;
}
try { try {
// Générer le lien questionnaire // Générer le lien questionnaire
const lienQuestionnaire = await getOrCreateQuestionnaireLink(apprenant.id, sequenceId); const lienQuestionnaire = await getOrCreateQuestionnaireLink(apprenant.id, sequenceId);