No era un simple leaderboard

Casos 28/05/2026

Un juego online, decenas de miles de jugadores y puntos llegando de todas partes: de las partidas y también de su marketplace de NFTs, con eventos nacidos en blockchain y servidos por Kafka. Cada jugador competía en varias tablas a la vez y los torneos disparaban el tráfico. El motor lo digiere todo, y cuando toca corregir puntos, recalcula sin descuadrar una sola tabla.

Categoría:

Casos

Tecnologías:

Rails 7, MongoDB, Kafka, Sidekiq, Redis, Node.js, WebSocket, PHP, Docker

Resumen del proyecto

El encargo

Una base de 30-40.000 jugadores y una media de 50-100 eventos por segundo, que en torneos se disparaba. Cada acción relevante debía reflejarse en las clasificaciones: las partidas del juego, sí, pero también la actividad en su marketplace, que otorgaba puntos por participar. Y todo servido por API a las aplicaciones, al instante.

No era un contador de puntos

La trampa de los leaderboards es pensar que son un sumatorio. Aquí no:

  • Varias fuentes con reglas distintas: un evento de partida no puntúa como una operación del marketplace.
  • Cada jugador vive en varias tablas a la vez: semanal, mensual, anual, histórica, temporadas, playoffs, modalidades de supervivencia… cada una con su corte temporal y su reglamento.
  • Los puntos no eran definitivos: había correcciones (eventos anulados, puntuaciones revisadas) y el sistema tenía que poder reprocesar sin descuadrar nada.

El origen de los eventos: streaming y blockchain

Aquí viene lo distinto: buena parte de los eventos nacían en una blockchain. El juego y su marketplace de NFTs funcionaban sobre contratos inteligentes (compras, ventas, recompensas de partida) y cada acción quedaba emitida como evento on-chain. Unos listeners escuchaban esos contratos, normalizaban lo que veían y lo publicaban en Kafka; el motor consumía los topics, clasificaba por fuente y persistía cada evento como un hecho.

El evento es la verdad; las tablas son cálculo derivado. Esa decisión permite corregir: si un evento se anula, se marca y las tablas afectadas se recalculan de los hechos. Y con blockchain de por medio tiene una gracia extra: los eventos llegan cuando la red los confirma, no cuando ocurren: el motor tenía que encajar hechos que aparecen con retraso y en desorden sin descuadrar ninguna tabla.

{
  "source": "marketplace",
  "wallet": "0x9f…c41",
  "action": "sale_completed",
  "points": 12,
  "occurred_at": "2023-04-16T19:22:31Z"
}

El gran reto: las agregaciones

Con decenas de tablas × periodos × 40.000 jugadores, la pregunta "¿cómo va la semanal?" es una agregación seria de MongoDB: filtrar millones de eventos por ventana temporal, agrupar por jugador, aplicar el reglamento de esa tabla, ordenar y paginar. Aquí nació el Aggregator de pipelines componibles que hoy uso en más proyectos (está en mi biblioteca de Rails):

Aggregate::Aggregator.new(Events::BattleArena)
  .add_stage(:match, { occurred_at: { "$gte": week_start, "$lt": week_end } })
  .add_stage(:group, { _id: "$wallet", points: { "$sum": "$points" } })
  .add_stage(:sort,  { points: -1 })
  .apply

Los recálculos pesados corrían como pools de jobs de Sidekiq, lotes en paralelo, con espera coordinada de que el lote completo terminara antes de publicar la tabla nueva.

Redis donde el tiempo real no compensa

No todas las tablas son igual de vivas. Las históricas y los máximos de referencia cambian despacio: recalcularlos por petición sería quemar CPU para dar siempre el mismo resultado. Ahí entra Redis con invalidación: el dato se sirve de caché y solo se recalcula cuando algo lo toca.

maximus_data = redis.get("#{leaderboard}/#{period}")   # máximos cacheados
# ... y al reprocesar eventos de ese periodo, la clave se invalida

Una API para servirlas todas

Todo se expone por una API RESTful: fuente, tabla, periodo, paginación, y metadatos (máximos, cortes temporales, totales) para que las apps pinten cada clasificación sin lógica propia. Un contrato único para decenas de tablas.

Un detalle de ingeniería honesto

Lo caro de un leaderboard no es sumar, es volver a sumar. Las correcciones y los reprocesos mandaron en el diseño: eventos como hechos inmutables marcables, cálculos derivados reproducibles y lotes que se pueden relanzar. Si tu clasificación no sabe rectificar, no está terminada; los torneos con premio lo dejan claro rapidísimo.

El resultado

Un motor que digirió años de partidas, torneos con picos de tráfico y cambios de reglas, sirviendo clasificaciones al instante a decenas de miles de jugadores. Y de regalo, piezas (agregaciones componibles, pools de jobs) que siguen trabajando hoy en otros proyectos.