fix: deduplicar webhooks duplicados con INSERT IGNORE + UNIQUE index en message_id
- conversations.message_id ahora tiene UNIQUE index (aplicado en BD prod) - saveMessage() usa INSERT IGNORE: si el mismo wamid llega dos veces en paralelo solo una llamada procesa el mensaje y llama al bot - La segunda llamada recibe rowCount=0 y hace continue sin pasar al bot - Elimina race condition que enviaba bienvenida + términos simultáneamente
This commit is contained in:
+17
-2
@@ -368,8 +368,14 @@ class WhatsAppWebhook {
|
||||
|
||||
// Filtrar campos según columnas existentes para evitar errores en esquemas antiguos
|
||||
$saveData = $this->filterColumns('conversations', $saveData);
|
||||
// Guardar mensaje y conservar el id de la conversación para posibles encolamientos
|
||||
// Guardar mensaje con INSERT IGNORE para deduplicar webhooks duplicados.
|
||||
// Si el message_id ya existe (segunda llamada paralela), rowCount=0 y saltamos el bot.
|
||||
$conversationId = $this->saveMessage($saveData);
|
||||
if (!$conversationId) {
|
||||
// Mensaje ya procesado por una llamada concurrente, ignorar
|
||||
error_log("[webhook] Duplicate webhook ignorado para message_id={$messageId}");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Si el media se encoló (no se pudo descargar), actualizar media_queue con el conversation_id
|
||||
if (!empty($mediaUrl) && empty($localFile) && in_array($messageType, ['image', 'audio', 'video', 'document', 'sticker'])) {
|
||||
@@ -469,7 +475,16 @@ class WhatsAppWebhook {
|
||||
}
|
||||
|
||||
private function saveMessage($messageData) {
|
||||
return $this->db->insert('conversations', $messageData);
|
||||
// INSERT IGNORE: si message_id ya existe (webhook duplicado), no inserta y devuelve 0
|
||||
$cols = implode(', ', array_map(fn($c) => "`{$c}`", array_keys($messageData)));
|
||||
$placeholders = implode(', ', array_map(fn($c) => ":{$c}", array_keys($messageData)));
|
||||
$sql = "INSERT IGNORE INTO `conversations` ({$cols}) VALUES ({$placeholders})";
|
||||
$stmt = $this->db->getConnection()->prepare($sql);
|
||||
$stmt->execute($messageData);
|
||||
if ($stmt->rowCount() === 0) {
|
||||
return 0; // duplicado
|
||||
}
|
||||
return $this->db->getConnection()->lastInsertId();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user