Antes de que un microservicio pueda hacer algo útil, tiene que hacer las mismas docena de cosas que ya hace cualquier otro servicio: leer configuración, autenticar al llamador, acceder a una base de datos, cachear un resultado, publicar un evento, obtener un secreto, emitir métricas y logs. Escrito una vez por servicio, esa plomería se duplica, se desvía y envejece mal.
La respuesta de Xeni es Falcon — un framework interno en Go sobre el que se construye cada servicio backend. Falcon se encarga de la infraestructura para que cada servicio se encargue solo de su dominio. Es la razón por la que un equipo pequeño puede operar muchos servicios sin levantar un grupo de plataforma detrás de cada uno.
Esta publicación es un recorrido por lo que hace Falcon, cómo está armado y las compensaciones que asumimos para construir una base compartida en lugar de muchas a medida.
Falcon aquí es el framework interno de Go de Xeni — no el proyecto open source en Python no relacionado con el mismo nombre. Todo lo que sigue es Go.
El costo de no tener uno
Escrito una vez por servicio, esa misma infraestructura se duplica y silenciosamente se desvía. Sin un chasis compartido, estos costos se repiten en cada servicio:
| Sin un chasis compartido | Qué ocurre |
|---|---|
| Boilerplate repetido | Cada equipo reimplementa enrutamiento, config, logging, auth, pools de BD, caché y métricas — semanas de trabajo antes de que el primer endpoint de negocio salga a producción. |
| Seguridad inconsistente | Los servicios validan tokens, resuelven tenants y enmascaran PII de forma diferente, y las brechas salen a la luz en auditorías y revisiones de incidentes. |
| Deriva operacional | Logs, etiquetas de métricas, sobres de error e IDs de correlación difieren por servicio, por lo que depurar fallos entre servicios se vuelve lento y frágil. |
| Dependencia de proveedor | Llamadas directas a SDK de AWS o GCP en código de producto hacen que las migraciones de nube o mensajería sean costosas y riesgosas. |
| Incorporación lenta | Los nuevos ingenieros aprenden una forma de stack diferente en cada repo en lugar de un contrato de plataforma único. |
| Fricción de escala | Connection pooling, bloqueos distribuidos, reintentos y eventing se reinventan — o se omiten bajo presión de entrega. |
Falcon existe para que los equipos de producto escriban lógica de dominio, mientras la plataforma se encarga de la corrección de infraestructura una sola vez — versionada, probada y reutilizada en todas partes.
Un chasis, cada servicio
La plataforma no es ni un monolito ni un conjunto disperso de apps no relacionadas. Cada vertical de producto y cada servicio de soporte — supply, payments, identity, AI — es un servicio separado construido sobre el mismo chasis Falcon. Los nuevos productos y capacidades son aditivos: heredan la base en lugar de reconstruirla.
Capa de interfaz
Web
API
MCP
SDK
Verticales de producto
Hoteles
Vuelos
Autos
Actividades
Resorts
Paquetes
Servicios
Suministro y descubrimiento
Servicios de proveedores
Servicios de agregadores
Búsqueda y catálogo
Auto Complete
Recomendaciones
Ofertas
Pagos y liquidación
Servicio de pago FIAT
Servicio de pago Crypto
Servicio de liquidación
Agentes de pago
Plataforma e IA
IDAM — identidad y confianza
Servicio backend de IA
Jobs de Temporal
Notificaciones
FALCON
chasis Go compartido · config · auth · data · cache · streaming · secrets · observability
Plano de datos y streaming — Postgres · Redis · OpenSearch · Kafka
Lo mismo se cumple en toda la flota. Más allá de los productos, la plataforma misma corre sobre Falcon — identity, configuration, accounts, reporting, operator tooling, payments, subscriptions, data migration, notifications, AI — y, para cada vertical, servicios de agregación que unifican docenas de servicios conector de proveedores. Cada uno de ellos es un servicio Falcon sobre el mismo chasis:
Servicios sobre Falcon
Identity (IDAM)
authN · authZ · trust
Config Management
config de runtime central
Account Service
orgs · accounts · users
Reporting Service
analytics e informes
Customer Admin
consola Command Center
Multi-Tenant Mgmt
herramientas de operador Xeni
Notification Service
email · SMS · push
AI Backend
agentes y servicio de modelos
Payment Service
fiat y crypto · liquidación
Data Migration
esquemas y movimientos de datos
Subscription Service
planes recurrentes y facturación
Aggregation Services
tie dozens of connectors — each a service · per vertical
FALCON
chasis Go compartido · config · auth · data · cache · streaming · secrets · observability
Plano de datos y streaming — Postgres · Redis · OpenSearch · Kafka
Una llamada, y la plomería está hecha
Un nuevo servicio Falcon comienza con casi ningún código de infraestructura. Creas el servidor, registras las rutas y le entregas el control al framework:
// main.go — create the server, register the routes, hand off to the framework.
func main() {
falcon := server.NewFalcon()
routers.AddRouters(falcon)
falcon.Fly()
}
// routers.go — one line per endpoint:
// method, API version, path, allowed roles, request body, handler
func AddRouters(falcon *server.Falcon) {
falcon.Add(
routes.POST, routes.V2, "/bookings",
[]routes.Role{constants.ScopeAdmin},
&model.BookingRequest{}, handlers.Booking,
)
// ...more routes...
}Las rutas viven en un routers.go — un solo falcon.Add por endpoint, declarando el método, versión de API, ruta, los roles permitidos para llamarlo, el cuerpo de solicitud a vincular y validar, y el handler. main.go casi no hace nada: crear el servidor, registrar las rutas y volar.
Cada handler tiene la misma firma — func(ctx) (interface{}, *APIError) — para que el framework pueda centralizar serialización, mapeo de error a HTTP, recuperación de pánico, propagación de request-id y correlación, y negociación de contenido. Todo lo que un handler necesita — configuración, clientes de base de datos y caché, clientes salientes — cuelga del context de la solicitud, recuperado con helpers server.Get*(ctx) en lugar de pasarse a mano. El handler en sí no hace el trabajo inline; compone la solicitud a partir de workers pequeños e independientes — donde vive la lógica de dominio real.
Desde el lado del ingeniero de producto, eso convierte una nueva funcionalidad en una lista de verificación corta y predecible:
- 01Define el modelo de solicitud — Falcon lo vincula y valida desde el cuerpo.
- 02Agrega una línea de ruta en
routers.go— método, versión, ruta, roles, cuerpo, handler. - 03Escribe un handler delgado que compone un flujo de trabajo.
- 04Escribe los workers — unidades pequeñas e independientes de lógica de dominio (un validator, una policy, los pasos).
- 05Conecta cualquier dependencia nueva — una base de datos, caché o servicio saliente — a través de config, no de código.
Todo lo demás — autenticación, autorización, logging estructurado, métricas, tracing, IDs de correlación, sobres de error, serialización, recuperación de pánico, y endpoints de health / metrics — el framework ya lo maneja. Esa es la habilitación: un ingeniero dedica su tiempo a la funcionalidad, no a la plomería.
El trabajo en segundo plano es igual de ligero: falcon.AddBatch(name, fn) registra un job de inicio que corre en su propia goroutine — el mismo cableado, sin una ruta HTTP.
La config es el cableado
Falcon es impulsado por configuración. Casi toda capacidad — una base de datos, una caché, un cliente HTTP saliente, un stream, un proveedor de nube — se instancia desde un group de config con nombre y un tipo declarado. Agregar una dependencia downstream es un cambio de configuración, no código nuevo.
La configuración es un formato plano de claves con puntos — <service>.<group>.<key>=<value> — cargado ya sea desde un archivo local o desde un servicio de config central (autenticado con un token de servicio a servicio). Falcon descubre groups por ese segmento del medio, que es cómo un solo servicio puede conectar varias bases de datos tipadas (por ejemplo groups separados tenantdb y coredb), múltiples streams o muchos clientes salientes puramente a través de config. Los getters tipados devuelven valores con defaults sensatos, de modo que el mismo binario se comporta correctamente en cada entorno — y los operadores pueden incluso cambiar la verbosidad de logs en tiempo de ejecución con PUT /loglevel/:level, sin reinicio requerido.
Baterías incluidas
Falcon incluye la infraestructura que un servicio en producción necesita, cada pieza detrás de una interfaz limpia:
| Área | Qué proporciona Falcon |
|---|---|
| API y middleware | Enrutamiento versionado basado en Gin (v1–v4), request-id / correlación, timeouts, recuperación de pánico, CORS, health / pprof y un endpoint de métricas |
| Datos | GORM sobre Postgres, MySQL y CockroachDB; OpenSearch (con soporte de reindexación) para búsqueda y catálogo |
| Caché | Redis con bloqueo distribuido, más AWS DAX |
| Mensajería | Una capa de streaming unificada — Kafka para publicar y consumir, con Kinesis y Google Pub/Sub en el lado de publicación |
| Flujos de trabajo | Un motor de pipeline de solicitudes interno, más Temporal para trabajo durable y de larga duración |
| Transportes | HTTP para llamadas entre servicios, con connection pooling y retry con backoff; con gRPC y los transportes de agentes de IA (SSE, MCP, agent-to-agent) en el roadmap |
| Nube | Una interfaz sobre AWS y GCP para almacenamiento, secretos y KMS |
| Seguridad | Cifrado AES-GCM y firmas Ed25519 (con codecs Base32/64/Hex/Ascii85), autorización multi-estrategia, auth de servicio a servicio y enmascaramiento de PII |
| Observabilidad | Logging estructurado (zap, con envío opcional a Loki), métricas Prometheus y eventos de auditoría |
| Concurrencia | Goroutine pooling con backpressure |
Nada de esto es novedoso por sí solo — el valor es que es uniforme. Cada servicio accede a una base de datos, emite una métrica o firma un payload de la misma forma, de modo que un ingeniero que ha trabajado en un servicio Falcon es inmediatamente productivo en el siguiente.
También es opt-in: cada capacidad se activa por servicio en configuración (falcon.<feature>.enabled=true), de modo que un servicio lean lleva solo lo que realmente usa y no paga nada por el resto.
Cómo fluye una solicitud
De extremo a extremo, cada solicitud pasa por las mismas etapas ordenadas, de modo que el comportamiento es predecible sin importar qué servicio la maneje:
- 01Ingress. La cadena de middleware estampa un request y correlation ID y aplica timeout, métricas y CORS.
- 02Autenticar. El token del llamador se valida — un token OAuth Bearer verificado contra un servicio de auth central, o un JWT verificado localmente — y se extraen sus scopes.
- 03Autorizar. Una verificación multi-estrategia resuelve la identidad y permisos del llamador, con búsquedas de política por tenant cacheadas en Redis — Xeni está consolidando estas estrategias en IDAM.
- 04Ensamblar contexto. El
contextacotado a la solicitud se enriquece con config, clientes de base de datos y caché, clientes salientes, identidad de tenant y usuario, e IDs de correlación. - 05Manejar. El handler de producto se ejecuta — típicamente componiendo el pipeline de flujo de trabajo de abajo.
- 06Responder. La salida se negocia por contenido — JSON por defecto, HTML y PDF para documentos orientados a humanos, y bytes crudos para archivos — con formateo automático de sobre de error. Las respuestas streaming (SSE, NDJSON) están en el roadmap; XML permanece disponible para consumidores legacy.
- 07Auditar. Los eventos de solicitud y flujo de trabajo, con campos sensibles enmascarados, se publican en el stream de notificaciones.
Cada solicitud corre la misma forma
Los servicios Falcon manejan solicitudes como un pipeline explícito en lugar de un enredo de código de handler:
Un handler compone ese pipeline como una cadena fluida — el motor de flujos de trabajo de Falcon:
resp, err := workflow.NewWorkflowEngine("Booking").
AddValidator(ctx, &InputValidator{}).
AddPolicy(ctx, &FraudPolicy{}).
AddWorker(ctx, &Booking{}, false).
AddWorker(ctx, &Payment{}, false).
AddErrorHandler(ctx, &ErrorHandler{}).
Execute(ctx)Su verdadero poder es que los workers son unidades de trabajo independientes. Cada uno implementa una interfaz pequeña — IsEligible, Skip y Execute — y el mismo worker puede componerse en diferentes flujos de trabajo para resolver diferentes necesidades de negocio. Un worker Payment escrito una vez se reutiliza en una reserva, un reembolso y una renovación de suscripción; un validator o fraud policy encaja en cualquier flujo que lo necesite.
El motor encadena las salidas de los workers, rastrea el estado por tarea en un WorkFlowStatus, emite un evento de flujo de trabajo en cada paso y enruta cualquier fallo al ErrorHandler registrado — dando a cada servicio estructura de handler consistente y lógica de negocio observable, testeable y componible.
Es el mismo patrón detrás del servicio de identidad de Xeni: una nueva capacidad es cuestión de escribir un worker y conectar una ruta.
Cambia el proveedor, no el código
Como las tecnologías de respaldo están detrás de interfaces, pueden cambiar sin tocar el código de producto. El proveedor de nube (AWS o GCP), la caché (Redis o DAX) y la columna vertebral de streaming (Kafka, Kinesis o Pub/Sub) se seleccionan por configuración y se resuelven a través de una factory. Un cambio de proveedor ocurre dentro del framework.
El efecto estratégico se compone: un nuevo servicio comienza con cero código de infraestructura, y el costo marginal del siguiente servicio — y del siguiente proveedor, mercado o producto — sigue cayendo a medida que el framework absorbe más del trabajo común.
Un patrón, servicios de propiedad cruzada
La plomería común es solo la mitad de lo que Falcon compra. La otra mitad es disciplina: porque el framework fija la forma de un servicio — un contrato de handler, un pipeline de solicitudes, una forma de alcanzar cada dependencia, un modelo de error y logging — cada servicio termina pareciéndose a todos los demás.
Esa uniformidad cambia cómo trabaja el equipo. Los ingenieros no están aislados en el servicio que les tocó construir; cualquiera que conoce un servicio Falcon puede leer, extender y depurar el siguiente. Los servicios son de propiedad cruzada en lugar de custodiados — lo que difunde conocimiento, elimina puntos únicos de fallo en el equipo y acorta la incorporación a días.
Importa más cuando algo se rompe. Los mismos logs, las mismas métricas y las mismas etapas de pipeline en cada servicio significan que quien esté de guardia puede orientarse dentro de un servicio desconocido y arreglarlo rápidamente — la resolución de problemas en vivo no espera a la única persona que lo escribió. Plomería compartida más patrones aplicados convierten "¿quién es el dueño de esto?" en "cualquiera de nosotros puede."
El resultado es apalancamiento: un equipo pequeño construye y opera una plataforma amplia, y la relación de servicios por ingeniero sigue mejorando a medida que el framework absorbe más del trabajo común.
Las compensaciones que asumimos
Una base compartida es una apuesta deliberada, y no es gratis:
- Riesgo concentrado. Un bug en Falcon puede llegar a cada servicio a la vez. Eso eleva el listón: el framework lleva un estándar más alto de revisión, pruebas y versionado cuidadoso que cualquier servicio individual.
- Exige profundidad. Falcon necesita experiencia real en Go y un equipo que trate el framework como un producto con su propio roadmap — no un proyecto secundario.
- Tiene que estar adelante. El framework debe anticipar lo que los equipos de producto necesitarán después; cuando se queda atrás, cada equipo siente la fricción.
Asumimos esto porque la alternativa es peor. Dejar que cada equipo re-resuelva configuración, auth, acceso a datos y observabilidad produce entregas más lentas, comportamiento inconsistente y una postura de seguridad imposible de razonar de forma uniforme. Centralizar las partes difíciles es lo que permite al resto moverse rápido.
Por qué se mantiene
- 01Aislar infraestructura del producto. Un servicio debe contener lógica de dominio y poco más.
- 02Hacer que cada servicio se vea igual. Un contrato de handler, un pipeline de solicitudes, una forma de alcanzar cada dependencia.
- 03Poner la topología en configuración. Agregar una base de datos o un cliente downstream es un cambio de config, no una reescritura.
- 04Ocultar proveedores detrás de ports. Nube, caché y streaming pueden cambiar sin que el código de producto lo note.
- 05Tratar el framework como producto. Aceptar el riesgo concentrado y pagarlo con revisión, pruebas y versionado.
Valor estratégico de un vistazo
Retrocediendo de la mecánica, el beneficio de negocio es directo:
| Objetivo de negocio | Cómo lo entrega Falcon |
|---|---|
| Entrega de producto más rápida | Los nuevos servicios comienzan con cero código de infraestructura — los equipos se enfocan en lógica de dominio. |
| Consistencia entre servicios | Auth, logging, métricas, eventos y manejo de errores se comportan de forma idéntica en todas partes. |
| Agilidad de proveedor y stack tecnológico | Nube, streaming, caché y preocupaciones de capa web están abstraídas detrás de Falcon. |
| Escala horizontal | Servicios stateless, connection pooling, bloqueo distribuido y desacoplamiento por streams. |
| Seguridad y cumplimiento | Auth centralizado, enmascaramiento de PII y criptografía respaldada por KMS aplicados de forma uniforme. |
| Madurez operacional | Métricas Prometheus, logs estructurados, endpoints de health y pprof, y eventos de auditoría listos para usar. |
Cierre
Falcon es fácil de subestimar porque, cuando funciona, no lo ves: los servicios simplemente comienzan con la plomería ya resuelta. Pero es la razón silenciosa por la que Xeni puede operar una plataforma amplia — identity, payments, search y las verticales de producto — sobre un chasis común en lugar de un montón de soluciones únicas.
En pocas palabras, Falcon es el tejido conectivo de la plataforma: convierte lo que de otro modo serían docenas de decisiones de infraestructura independientes por servicio en un contrato único, versionado e impulsado por config. Por eso lo tratamos como un producto interno de primera clase — con maintainers dedicados, una cadencia de release estable y una política clara de deprecación para rutas legacy — no una utilidad compartida que nadie posee.
El framework es el apalancamiento: resolver infraestructura una vez e heredarla en todas partes. El ejemplo más claro de un servicio construido enteramente sobre ese apalancamiento es la capa de identidad de Xeni — el tema de la publicación complementaria, Dentro de IDAM.
Escrito para el blog de Ingeniería Xeni. Describe el framework Falcon a julio de 2026. El ejemplo de código es ilustrativo de la forma de la API del framework.