¿Cómo evitar que dos personas compren el último boleto?
Share

In this article
- 01¿Por qué una lectura seguida de escritura sobre el conteo de boletos genera sobreventa?
- 02¿Por qué usar un bloqueo pesimista a nivel de fila para los últimos boletos?
- 03¿Cómo evita una reserva en Redis que los checkouts abandonados bloqueen el inventario?
- 04¿Qué pasa si el webhook de pago llega dos veces?
- 05¿Esto funciona bajo carga?
Decrementa el conteo de boletos dentro de una transacción corta en la base de datos que mantiene un bloqueo pesimista a nivel de fila, y reserva cada boleto en Redis con un tiempo de vida (TTL). La escritura del segundo comprador espera unos milisegundos detrás del primero, y luego ve que ya no hay boletos disponibles. Las reservas de checkouts abandonados se liberan automáticamente cuando expira el TTL.
¿Por qué una lectura seguida de escritura sobre el conteo de boletos genera sobreventa?
Dos solicitudes pueden leer el mismo conteo restante de uno, ambas pasan la verificación y ambas escriben una venta. El conteo era correcto al leerlo pero estaba desactualizado al escribir, por lo que un boleto se vende dos veces. Cualquier operación de lectura seguida de escritura sobre inventario compartido tiene esta condición de carrera a menos que la escritura sea atómica o esté bloqueada.
Un reintento optimista simple soluciona el problema de corrección, pero comienza a generar sobrecarga cuando los últimos boletos de un evento popular son solicitados por una ráfaga de checkouts: cada cliente comprador que pierde debe reintentar todo el proceso de checkout, no solo la escritura.
¿Por qué usar un bloqueo pesimista a nivel de fila para los últimos boletos?
Un bloqueo pesimista hace que el segundo escritor espere brevemente en lugar de fallar y reintentar a ciegas. Para una fila muy solicitada por muchos compradores al mismo tiempo, unos pocos milisegundos de espera son más baratos que reintentos completos de checkout. El bloqueo se mantiene solo durante la corta transacción que decrementa el conteo de boletos.
¿Cómo evita una reserva en Redis que los checkouts abandonados bloqueen el inventario?
Cuando un comprador inicia el checkout, se reserva el boleto en Redis con un TTL. Si paga, la reserva se convierte en venta. Si se va, la clave expira y el boleto vuelve automáticamente al inventario. Nadie puede retener un boleto simplemente abriendo una pestaña de checkout y alejándose.
¿Qué pasa si el webhook de pago llega dos veces?
No pasa nada adicional. El manejador del webhook es idempotente, identificado por el ID del pedido, y su único trabajo es publicar un evento de pago confirmado en RabbitMQ. Una entrega reintentada encuentra el pedido ya procesado, por lo que un boleto nunca se emite dos veces. Un consumidor posterior genera el boleto y envía la confirmación.
El mismo patrón se explica paso a paso en la nota sobre webhooks idempotentes.
¿Esto funciona bajo carga?
En pruebas en FindYourVibe, el checkout se mantuvo correcto con más de 300 compradores concurrentes en un solo lanzamiento de evento, sin sobreventa de boletos. Las decisiones de diseño que permitieron esto son el bloqueo a nivel de fila en los últimos boletos, la reserva en Redis con TTL y el webhook idempotente que alimenta una cola.
Bloqueo pesimista a nivel de fila en los últimos boletos de un evento
Reserva en Redis con TTL, evitando la sobreventa
RabbitMQ desacopla la emisión de boletos de la respuesta del webhook
Webhook de pago idempotente identificado por ID de pedido
Publicado originalmente en sakshamjain.codes/blog/stop-two-people-buying-the-last-ticket. ¿Necesitas esto implementado? Consulta mis servicios en NexoRush o envíame un mensaje.