Control de concurrencia para saldos de puntos: cómo evitar doble gasto
Respuesta breve: para evitar doble gasto, la verificación de saldo y el registro del débito deben formar una decisión atómica o serializable por cuenta. Leer el saldo y descontar después en otra operación deja una carrera. Un ledger inmutable, claves idempotentes y reservas completan la protección.
PostgreSQL documenta que los niveles de aislamiento permiten anomalías diferentes y que Serializable puede abortar transacciones para preservar un resultado equivalente a algún orden serial. Eso exige reintentos correctos; un error de serialización no debe convertirse en otro canje.
El reto no se resuelve con un cache ni con esconder el botón. Dos POS, una app y un proceso batch pueden actuar a la vez. La invariante debe vivir en la capa que confirma el movimiento económico y producir evidencia para explicar el resultado.
Escriba la invariante antes del mecanismo
La regla puede ser saldo disponible no negativo, límites de sobregiro explícitos y una sola aplicación por intención. Debe incluir reservas y puntos pendientes.
Defina disponible, contable, reservado y vencido. Aclare unidad, cuenta y momento de evaluación.
Una invariante estricta reduce flexibilidad para excepciones; excepciones implícitas destruyen consistencia. Modele ajustes autorizados.
Construya ejemplos con emisión pendiente, reserva, canje y reversa hasta que todos calculen el mismo disponible.
Para gobernar escriba la invariante antes del mecanismo, asigne una métrica de calidad y otra de resultado. La primera muestra si el mecanismo operó como fue diseñado; la segunda indica si ayudó al objetivo. Mezclarlas puede hacer que una campaña exitosa oculte errores operativos, o que una ejecución impecable se confunda con impacto comercial.
Para que escriba la invariante antes del mecanismo sea sostenible, automatice validaciones estables y conserve revisión en decisiones ambiguas. El objetivo no es eliminar personas, sino reservar su criterio para excepciones y cambios. Las alertas deben llegar con contexto suficiente para decidir, no limitarse a anunciar que algo falló.
Use un ledger como evidencia de movimientos
El saldo es una proyección de emisiones, débitos, expiraciones, reversas y ajustes. El ledger conserva cada movimiento y su relación causal.
Haga inmutables los registros confirmados; corrija con movimiento inverso. Mantenga idempotencia y referencia de transacción.
Calcular desde todo el ledger es costoso; una proyección acelera lectura y debe reconciliarse con la fuente.
Reconstruya cuentas seleccionadas y confirme que proyección y suma de movimientos coinciden.
La documentación de use un ledger como evidencia de movimientos debe caber en una decisión utilizable: propósito, entradas, regla, salida, propietario, excepción y fecha de revisión. El detalle adicional puede vivir en evidencias enlazadas. Esta jerarquía mantiene el trabajo auditable sin convertir cada cambio en una tarea burocrática imposible de sostener.
Una revisión útil de use un ledger como evidencia de movimientos termina con una decisión binaria sobre el siguiente paso: avanzar con el alcance probado o mantenerlo limitado. Para evitar discusiones retrospectivas, anote la evidencia disponible, los datos todavía desconocidos y la fecha de la próxima revisión. No convierta una ausencia de incidentes en prueba automática de calidad.
Mantenga verificación y débito en una frontera atómica
La operación debe bloquear, comparar o serializar la fila lógica antes de confirmar el débito. El saldo observado fuera de esa frontera es informativo.
Use una condición de actualización o transacción que falle si ya no existe valor suficiente. Devuelva un resultado estable.
La transacción protege consistencia y puede aumentar contención. Mantenga corta la sección crítica y saque llamadas externas.
Lance dos débitos que juntos exceden el saldo y compruebe que solo uno confirma sin saldo negativo.
Finalmente, revise mantenga verificación y débito en una frontera atómica desde la perspectiva de la persona afectada. Debe poder entender qué ocurrió, corregir información cuando corresponda y encontrar una ruta de ayuda. Una operación técnicamente consistente puede seguir siendo mala si sorprende, bloquea o comunica de forma distinta a la regla que realmente ejecuta.
La escala de mantenga verificación y débito en una frontera atómica debe aumentar por cohortes o unidades controlables. Compare una versión estable con la nueva, mantenga un canal para incidentes y defina de antemano el criterio de reversa. Así el despliegue produce evidencia sin exponer de inmediato a toda la población ni depender de una lectura tardía del resultado.
Elija control pesimista u optimista
Un lock pesimista serializa por cuenta; una versión optimista detecta cambios al actualizar. Ambos funcionan si el conflicto produce reintento o rechazo seguro.
Use locks cuando conflicto es frecuente y operación corta; versiones cuando es raro y se puede reintentar. Mida espera y abortos.
Locks previenen trabajo perdido y crean colas o deadlocks; optimismo escala y repite trabajo bajo contención.
Pruebe una cuenta normal y una cuenta corporativa de alta actividad para comparar latencia y conflicto.
Para evaluar elija control pesimista u optimista sin depender de impresiones, conserve una línea base, la regla aplicada, el resultado observado y la excepción. Ese registro permite separar fallos de datos, fallos de diseño y fallos de ejecución. También facilita explicar por qué una decisión fue válida en su momento aunque el contexto cambie después.
Una señal temprana de problema en elija control pesimista u optimista es el crecimiento de ajustes manuales, campos libres o reglas temporales sin fecha. Esas soluciones pueden resolver un caso y esconder una deuda. Agrupe motivos, identifique patrones y cambie el diseño cuando una excepción deja de ser excepcional.
Use aislamiento con conocimiento de anomalías
Read Committed, Repeatable Read y Serializable ofrecen garantías distintas. La aplicación debe conocer qué lecturas y escrituras forman la decisión.
Demuestre la invariante con pruebas concurrentes. En Serializable, reintente toda la transacción con la misma intención.
Mayor aislamiento simplifica razonamiento y puede reducir throughput. Un nivel menor exige locks o condiciones explícitas.
Ejecute la carrera en el motor real y capture el plan, locks, abortos y estado final.
La señal de madurez en use aislamiento con conocimiento de anomalías no es tener más opciones, sino poder repetir una decisión y obtener un resultado comprensible. Defina quién revisa la evidencia, cuándo se reevalúa y qué condición obliga a detenerse. Si esas respuestas viven solo en una persona, el proceso todavía no es operable.
En la práctica, use aislamiento con conocimiento de anomalías cruza negocio, operación y tecnología. Negocio define el resultado y los límites; operación confirma que el procedimiento puede sostenerse; tecnología preserva estados y evidencia. Cuando una de esas funciones decide aislada, el flujo puede parecer correcto en su herramienta y fallar en la experiencia completa.
Modele reservas con vencimiento
Una reserva reduce el disponible antes de confirmar un proceso externo. Debe tener identificador, monto, estado, expiración y relación con el débito final.
Confirme o libere de forma idempotente. Un job de expiración no debe liberar una reserva que ya se confirmó.
Reservar evita sobreventa y retiene valor durante fallos. Use timeout basado en recorrido y una ruta de consulta.
Falle entre reserva y confirmación; observe expiración, reintento y respuesta al cliente.
Un piloto de modele reservas con vencimiento debe incluir casos normales y casos que contradigan la expectativa del equipo. Observe no solo si el flujo termina, sino si conserva identidad, tiempo, motivo y responsabilidad. Esos datos convierten la prueba en aprendizaje y evitan escalar una configuración que funciona únicamente con ejemplos ideales.
La responsabilidad sobre modele reservas con vencimiento no termina en el equipo que configura. Soporte necesita explicar resultados, datos debe rastrear entradas, seguridad y legal revisan cuando corresponde, y finanzas valida movimientos de valor. Un propietario único coordina esas contribuciones y evita que una excepción viaje indefinidamente entre áreas.
Haga la intención idempotente
Cada canje recibe una clave que identifica la misma solicitud a través de reintentos. El servidor conserva parámetros y resultado.
Rechace reutilización con monto o recompensa distinta. Retenga el registro durante toda la ventana de duplicación posible.
Una clave por request técnico no evita que el cliente genere otra; vincúlela con una intención de negocio visible.
Repita desde POS y app con la misma referencia y confirme un solo movimiento y la misma respuesta.
Antes de automatizar haga la intención idempotente, ejecute el procedimiento manualmente con un volumen pequeño y documente cada decisión. La automatización es apropiada cuando reduce trabajo repetible sin borrar contexto ni rutas de corrección. Si las excepciones siguen cambiando cada semana, conviene estabilizar primero la política y los datos.
El cierre de haga la intención idempotente debe incluir evidencia de extremo a extremo: entrada conocida, regla versionada, salida observada y comunicación coherente. Si solo se valida la pantalla final, quedan invisibles transformaciones y fallos intermedios. Conserve una muestra reproducible para futuras regresiones y capacitación.
Observe contención, deadlocks y correcciones
Mida espera por lock, abortos, reintentos, cuentas calientes, reservas antiguas y diferencias entre ledger y proyección. Las alertas necesitan contexto.
Defina umbrales y respuesta. Ordene locks de forma consistente y limite reintentos con jitter.
Eliminar toda contención no es realista; ocultarla crea latencia impredecible. Diseñe capacidad y excepción para hotspots.
Haga una prueba de carga con distribución realista y cierre cada inconsistencia con un movimiento trazable, nunca editando el saldo.
El control de observe contención, deadlocks y correcciones debe ser proporcional al impacto. Una decisión reversible y de bajo valor admite una ruta más ligera que otra que mueve dinero, restringe acceso o utiliza información sensible. Hacer explícita esa diferencia protege la experiencia y concentra revisión humana donde realmente cambia el riesgo.
Conviene representar observe contención, deadlocks y correcciones con un caso aceptado, uno rechazado y uno indeterminado. El tercero es especialmente valioso porque obliga a diseñar qué ocurre cuando faltan datos o dos reglas compiten. Una política madura no inventa certeza: conserva el estado, pide evidencia y limita la acción hasta resolverlo.
Cómo evaluar el control de saldo con Lealto
Lealto debe confirmar el modelo de ledger, transacción e idempotencia aplicable al alcance. Integraciones y sistemas externos también deben conservar la intención; una confirmación visual del POS no sustituye la decisión del sistema de registro.
La prueba mínima es concurrente: dos o más solicitudes sobre el mismo saldo, fallos en las fronteras y reconstrucción posterior. Si el resultado no puede explicarse movimiento por movimiento, falta control.
Fuentes para profundizar
– PostgreSQL: Transaction isolation: https://www.postgresql.org/docs/current/transaction-iso.html
– PostgreSQL: Concurrency control: https://www.postgresql.org/docs/current/mvcc.html
– PostgreSQL: Explicit locking: https://www.postgresql.org/docs/current/explicit-locking.html
– Lealto: conciliación y reclamos: https://lealto.com/blog/programas-de-lealtad/conciliacion-reclamos-saldos-programas-lealtad/
Contáctenos
Construyamos su estrategia de lealtad
