Gestionar eventos de webhook fuera de orden

Estoy construyendo un flujo de trabajo de n8n que recibe eventos de webhook de un servicio externo. El mismo registro puede generar múltiples eventos, pero a veces llegan fuera de orden debido a reintentos o retrasos de red.
Ejemplo: Pedido Actualizado → estado = enviado
Pedido Actualizado → estado = entregado
pero n8n recibe entregado primero y enviado después.
Mi actualización actual de PostgreSQL es simplemente:
UPDATE orders
SET status = $2,
updated_at = NOW()
WHERE id = $1;
¿Me recomendarías usar una marca de tiempo de evento, número de secuencia o columna de versión para que un evento más antiguo no pueda sobrescribir datos más recientes?
¿Cómo implementarías eso de manera segura en PostgreSQL?

Describe el problema/error/pregunta

¿Cuál es el mensaje de error (si lo hay)?

Por favor, comparte tu flujo de trabajo

(Selecciona los nodos en tu lienzo y usa los atajos de teclado CMD+C/CTRL+C y CMD+V/CTRL+V para copiar y pegar el flujo de trabajo.)

Comparte el resultado devuelto por el último nodo

Información sobre tu configuración de n8n

  • versión de n8n:
  • Base de datos (predeterminado: SQLite):
  • configuración n8n EXECUTIONS_PROCESS (predeterminado: own, main):
  • Ejecutando n8n mediante (Docker, npm, n8n cloud, aplicación de escritorio):
  • Sistema operativo:

@Gabby_Timothy usa un número de secuencia o número de versión siempre que la API proporcione uno. Es mucho más seguro que confiar solo en marcas de tiempo.

UPDATE orders
SET
status = $2,
version = $3,
updated_at = NOW()
WHERE id = $1
AND version < $3;

Si un evento más antiguo llega después, la condición version < $3 evita que sobrescriba el estado más nuevo.

Si la API solo proporciona marcas de tiempo, puedes usar: UPDATE orders
SET status = $2,
updated_at = $3
WHERE id = $1
AND updated_at < $3;

también almacena los eventos entrantes por separado si necesitas auditoría o reproducción.

Si uso una columna version para evitar que eventos antiguos sobrescriban los más recientes, ¿cómo manejarías dos eventos webhook que llegan casi al mismo tiempo?

¿Sería suficiente solo version < $3, o también debería usar una transacción de PostgreSQL o bloqueo a nivel de fila para que la actualización sea completamente segura bajo ejecuciones concurrentes de n8n? @Keira_Becky

@Gabby_Timothy version < $3 suele ser suficiente para evitar que un evento más antiguo sobrescriba uno más nuevo, porque PostgreSQL evalúa la condición atómicamente.

UPDATE orders
SET
status = $2,
version = $3,
updated_at = NOW()
WHERE id = $1
AND version < $3;

Si dos ejecuciones de n8n llegan al mismo pedido casi simultáneamente, PostgreSQL maneja la actualización de la fila secuencialmente. Una vez que se escribe la versión más alta, la actualización más antigua ya no satisface version < $3.

Agrega FOR UPDATE solo cuando necesites realizar múltiples operaciones de base de datos dependientes en la misma transacción.

Hola @Gabby_Timothy
Una UPDATE con protección no coincide con ninguna fila cuando la fila aún no existe, Postgres reporta UPDATE 0 sin error, y el evento desaparece. La entrega fuera de orden hace que ese caso sea habitual, ya que el evento que crea el registro puede llegar después del que lo actualiza. Combina insert y protección en una sola instrucción:

INSERT INTO orders (id, status, version, updated_at)
VALUES ($1, $2, $3, NOW())
ON CONFLICT (id) DO UPDATE
SET status = EXCLUDED.status, version = EXCLUDED.version, updated_at = NOW()
WHERE orders.version < EXCLUDED.version
RETURNING *;

id necesita una clave principal o un índice único para que ON CONFLICT se dirija correctamente. Una fila faltante se inserta, un evento más nuevo se aplica, uno obsoleto se omite, y la comparación estricta < también ignora una repetición exacta de la misma versión. Postgres bloquea la fila en conflicto cuando se ejecuta DO UPDATE y garantiza un resultado atómico de insert-or-update bajo concurrencia, así que esto también se aplica a tu caso de llegada simultánea. RETURNING solo devuelve una fila que la instrucción escribió, un evento obsoleto vuelve vacío, así que el siguiente nodo puede ramificarse según si algo fue aplicado.
En el nodo de Postgres ejecútalo con Query Parameters y establece Query Batching en Independently. Single Query agrupa todos los elementos entrantes en una sola instrucción, y dos eventos para el mismo pedido en un lote fallan con “ON CONFLICT DO UPDATE command cannot affect row a second time”.