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