Planteamiento y alcance
Asume 20.000 inquilinos (tenants) y 1 millón de operaciones por hora, con picos cortos de 10x y una decisión de autorización p95 por debajo de 100 ms. Los clientes compran créditos antes de ejecutar operaciones. Cada operación tiene un costo variable, las solicitudes pueden llegar de forma concurrente y la entrega de eventos de uso es de al menos una vez (at-least-once). El diseño debe evitar saldos negativos y cobros dobles mientras preserva un registro de auditoría. Este es un libro mayor de valor comprado, no un limitador de tasa (rate limiter) ni un sistema de facturación de suscripciones recurrentes.
Qué está evaluando el entrevistador
- Separar los movimientos de crédito inmutables de un modelo de lectura rápida de saldo.
- Hacer que las operaciones de autorización, captura, liberación, reembolso y otorgamiento sean idempotentes.
- Manejar solicitudes concurrentes, eventos demorados, reintentos, expiraciones y conciliaciones.
- Explicar límites de consistencia, inquilinos con alta carga (hot tenants), observabilidad y recuperación.
Preguntas clarificadoras para hacer
Pregunta si los créditos expiran, si una operación fallida puede reservar y luego liberar, cómo se aprueban los reembolsos, si el costo se conoce antes de la ejecución y si un inquilino puede gastar en múltiples regiones. Confirma la latencia de decisión requerida y si se permite la sobreautorización temporal.
La respuesta de 30 segundos
Utilizaría un libro mayor inmutable y de solo anexado (append-only) de otorgamientos, reservas, capturas, liberaciones, reembolsos y expiraciones. Una proyección transaccional de saldo soporta lecturas rápidas, mientras que una clave de idempotencia hace que cada mutación sea repetible. La autorización verifica atómicamente los créditos disponibles y crea una reserva con una expiración; el trabajo exitoso la captura, las fallas la liberan y un recuperador maneja las reservas abandonadas. Un outbox, eventos reproducibles y conciliación comparan la proyección con el libro mayor y reparan desviaciones con entradas compensatorias auditables.
Análisis detallado paso a paso
1. Modelar el estado de los créditos
Mantén una clave de inquilino/cuenta, unidades de crédito enteras, una secuencia de libro mayor y una proyección que contenga los totales otorgados, reservados, capturados, liberados, reembolsados y expirados. Almacena cada mutación con operationid, idempotencykey, motivo, actor y marca de tiempo. Nunca edites una entrada antigua; las correcciones anexan una entrada compensatoria.
2. Autorizar sin doble gasto
Usa una sola transacción o una actualización condicional linearizable para la clave caliente del inquilino: crea una reserva solo cuando los créditos disponibles sean al menos el costo solicitado. Una clave de idempotencia repetida devuelve la decisión original; una clave reutilizada con parámetros diferentes es rechazada. Mantén la expiración de la reserva y las transiciones de estado de forma condicional para que la captura y la liberación no puedan ganar ambas.
3. Conectar la ejecución y los eventos
La solicitud de negocio transporta el identificador de reserva. La captura sigue al éxito confirmado; la liberación sigue a una operación fallida o cancelada. Los eventos de uso pueden duplicarse o demorarse, por lo que los consumidores desduplican por event_id y concilian reservas desconocidas en lugar de decrementar ciegamente un contador. Un outbox publica los cambios confirmados del libro mayor después de la transacción.
4. Escalar, alternativas y recuperar
Particiona por inquilino, enruta a un inquilino hacia un escritor principal (home writer) y aísla inquilinos excepcionalmente calientes con control de admisión o un flujo de comandos serializado. Una transacción relacional es la opción más simple cuando la tasa de escritura de cada inquilino es moderada; un flujo de comandos con event sourcing es preferible para inquilinos muy calientes cuando la reproducción y el orden importan más que la simplicidad de consulta. Las lecturas pueden usar réplicas solo cuando se muestra su nivel de obsolescencia. Un limpiador (sweeper) expira reservas abandonadas y la reproducción reconstruye la proyección a partir del libro mayor. Las alertas cubren disponibilidad negativa, captura después de la expiración, retraso de reproducción y diferencias de conciliación.
Un ejemplo sólido de respuesta
Aclararía la expiración, la autoridad de reembolso, el gasto multirregión y si el costo se conoce antes de la ejecución. La fuente de la verdad es un libro mayor inmutable por inquilino; la tabla de saldos es una proyección reconstruible. authorize reserva atómicamente el costo bajo una clave de idempotencia y expiración, capture convierte esa reserva después del éxito y release o la expiración la devuelven. Los eventos duplicados o demorados se desduplican y concilian. Las escrituras afines al inquilino evitan el doble gasto entre regiones; si una región debe operar de forma independiente, recibe una asignación acotada cuya deuda se concilia explícitamente. Cada corrección es una entrada compensatoria de solo anexado.
Errores comunes
- Solo un contador mutable → los reintentos y reembolsos no se pueden auditar → anexa una entrada inmutable con una identidad de operación.
- Cobrar al recibir la solicitud → el trabajo fallido aún gasta créditos → reserva primero y captura solo después del éxito.
- Reintento tratado como nuevo consumo → se cobra una operación dos veces → reutiliza la misma clave de idempotencia.
- La reserva nunca se recupera → los workers caídos bloquean créditos para siempre → añade expiración y un limpiador condicional.
- Lectura eventualmente consistente entre regiones → dos escritores pueden sobregastar → usa un solo escritor o un presupuesto regional explícito.
- Editar filas antiguas para corregir el historial → el registro de auditoría pierde confiabilidad → anexa una entrada compensatoria.
Preguntas de seguimiento y respuestas
El cliente agotó el tiempo de espera (timeout) después de la autorización. ¿Qué sucede?
Consulta la reserva o reintenta la siguiente transición con la misma clave de idempotencia. No vuelvas a autorizar hasta que la reserva original sea capturada, liberada o haya expirado.
¿Cómo procesas un reembolso después del cierre de mes?
Anexa una entrada de reembolso haciendo referencia a la captura original y a un registro de aprobación. La proyección incrementa los créditos disponibles, mientras que el libro mayor preserva ambos eventos y su orden.
¿Pueden dos regiones gastar de la misma cuenta concurrentemente?
Prefiere un único escritor o región principal del inquilino para una semántica estricta de no doble gasto. Si se requiere gasto local acotado, asigna presupuestos regionales explícitos y concilia la deuda; especifica el sobregiro temporal máximo.
¿Cómo demuestras que el saldo es correcto?
Reproduce periódicamente el libro mayor, compara el monto disponible derivado con la proyección y compara las capturas con los resultados de las operaciones de negocio. Emite una entrada compensatoria idempotente y un registro de auditoría para cada reparación.