Índice del curso
Lección 09 — El hilo entre servicios
Por Dorian Chávez · cofundador y Chief Executive Officer de Hábil ·
Lo que vas a lograr: que cada orden lleve un id de correlación que la acompañe de la tienda al router, del router a int-rest y de int-rest a la API, para que puedas encontrarla en cualquier punto del recorrido buscando un solo valor.
Antes de empezar necesitas: la lección 08 terminada y el ambiente de la 00 encendido:
docker compose -f infra/compose.yaml up -d --wait # desde la carpeta raíz de la práctica
Lo nuevo de hoy, en una frase
En la 08 la orden pasó por tres servicios, y cada uno escribió en su propio log. Si mañana una tienda reclama «mi orden no llegó», ¿cómo juntas los renglones de los tres logs que hablan de esa orden? Hoy le pones un hilo: un id que cada servicio recibe y le pasa al siguiente.
La imagen: el número de guía de un paquete. Pasa por la sucursal, el centro de distribución y el repartidor, y en cada lugar lo anotan. Con ese número sabes dónde estuvo. Si una sucursal no lo anota, desde ahí el paquete se vuelve invisible.
El sobre, completo
En la 08 viste los encabezados ce-* sin usarlos. Hoy los lees:
| Encabezado | Qué dice | Para la orden 1003 |
|---|---|---|
ce-specversion |
Qué versión de CloudEvents usa el sobre | 1.0 |
ce-id |
Qué evento es este, uno solo | orden-1003-creada |
ce-type |
De qué tipo es el evento | mx.tienda.orden.creada |
ce-source |
Dónde pasó | /tiendas/T-022 |
ce-subject |
De qué cosa habla: la orden | 1003 |
ce-correlationid |
El hilo: une todo lo que pasa por culpa de una misma petición | lo decide la tienda, o el router |
ce-id y ce-correlationid parecen lo mismo y no lo son. El ce-id nombra un evento. El hilo sigue a una
petición de la tienda por todos los servicios que toca. Cuando una orden genere varios eventos (creada, embarcada,
entregada), cada uno tendrá su ce-id propio, y todos podrán compartir el mismo hilo.
ce-correlationid no es uno de los campos base de CloudEvents: es una extensión, un campo que se agrega al
sobre. La norma permite agregar extensiones.
1. Prepara tu carpeta
cd lecciones/09-el-hilo-entre-servicios
cp -R inicio mio
2. Lee de dónde sale el hilo
Abre mio/orden-router/orden-router.camel.yaml. Arriba hay un paso choice:
| Si la tienda… | El router… |
|---|---|
manda el encabezado X-Correlation-Id |
usa ese mismo id como hilo |
| no lo manda | inventa uno nuevo, un UUID (un número al azar tan largo que, en la práctica, no se repite) |
Y al final, el router se lo devuelve a la tienda en la respuesta. Así la tienda tiene con qué preguntar por su orden.
Fíjate en el comentario: el id se guarda en una variable antes de limpiar encabezados. Ése es el corazón de la lección.
3. Predice
La ruta de inicio/ tiene tres TODO, y por ahora ningún servicio pasa el hilo al siguiente. Contesta en un papel:
- Si la tienda manda la orden 1003 con el id
mi-hilo-1, ¿en qué punto del recorrido se pierde: en el router, en int-rest o en la API? - ¿La tienda recibe de vuelta su id, aunque se pierda en el camino?
Compruébalo:
./verifica inicio
Salen tres marcas rojas, y una dice La API no recibió el hilo de la 1003 (anotó: correlacion=-). El guion es como
la API escribe «no me llegó ninguno». El router sí anotó el hilo y la tienda sí lo recibió de vuelta: el hilo se
pierde en el primer servicio que no lo reenvía, justo después del router.
4. Escribe los tres pasos
Son tres TODO y los tres son la misma idea: recibir el hilo y pasarlo.
1. En el router: ponlo en el sobre. En mio/orden-router/orden-router.camel.yaml, donde dice TODO, agrega un
setHeader con el nombre ce-correlationid y el valor de la variable correlacion. Usa como modelo el setHeader
de ce-subject, que está unos renglones arriba.
2. En int-rest: guárdalo antes de que se borre. En mio/int-rest/int-rest.camel.yaml, el primer TODO. Agrega un
setVariable llamado correlacion con el valor ${header.ce-correlationid}. Tiene que ir ahí, arriba: unos
pasos más abajo está removeHeaders, que borra todos los encabezados que llegaron.
3. En int-rest: pásaselo a la API. El segundo TODO. Agrega un setHeader llamado X-Correlation-Id con el valor
de la variable correlacion. Va después del removeHeaders, junto a los demás encabezados de la llamada a la API.
5. Síguelo con tus ojos
Desde la carpeta de la lección, levanta los servicios y mira sus logs:
DONDE=mio docker compose -f compose.yaml up -d
DONDE=mio docker compose -f compose.yaml logs -f
En otra terminal, desde la raíz de la práctica, haz de tienda con tu propio hilo:
curl -i -XPOST localhost:8080/ordenes -H 'Content-Type: application/json' \
-H 'X-Correlation-Id: mi-hilo-1' -d @datos/ordenes/orden-1003.json
Busca mi-hilo-1 en tres lugares:
| Dónde | Qué buscar |
|---|---|
La respuesta de curl |
El encabezado X-Correlation-Id: mi-hilo-1 |
| Los logs del router y de int-rest | correlacion=mi-hilo-1 en sus renglones |
| El log de la API | docker compose -f infra/compose.yaml logs api-pedidos | grep mi-hilo-1 |
Si en los tres aparece el mismo valor, el hilo está completo. Ahora manda la orden sin el encabezado
X-Correlation-Id. ¿Qué id te devolvió la tienda? Búscalo en los logs: debe ser el mismo en todos.
Al terminar, apaga los servicios:
DONDE=mio docker compose -f compose.yaml down
6. El error más común: leerlo tarde
Haz la prueba: en int-rest, mueve tu setVariable de la correlación para que quede debajo del removeHeaders.
Apaga, levanta otra vez y manda la orden con mi-hilo-1.
La tienda recibe su id de vuelta, el router lo anota, pero int-rest escribe correlacion= (vacío) y la API,
correlacion=-. Cuando int-rest fue a leer el encabezado, removeHeaders ya lo había borrado. No hay error ni
alarma: el hilo se corta en silencio.
Por eso la regla es: lo que necesites de la llamada que entró, guárdalo en una variable antes de limpiar. Las variables no se borran con los encabezados. Regresa tu paso a su lugar.
7. Comprueba
./verifica
verifica reinicia la API, levanta los dos servicios y manda dos órdenes: la 1003 con un hilo propio y la 1001 sin
ninguno. Está terminada cuando ves las ocho marcas verdes:
✅ Arrancaron el router e int-rest
✅ La tienda mandó la 1003 y la respuesta final fue 201
✅ El router anotó el hilo tienda-…
✅ int-rest recibió el hilo en el sobre
✅ La API registró la 1003 con el mismo hilo: se puede seguir de punta a punta
✅ La tienda recibió de vuelta su mismo id
✅ Los encabezados del sobre (ce-*) no salieron hacia la tienda
✅ Sin id de la tienda, el router inventó … y llegó igual a la API
Donde ves … aparece el id de esa corrida: verifica usa uno nuevo cada vez.
La séptima revisa algo que no escribiste tú: el sobre ce-* es para los servicios de adentro, y el router lo
borra antes de contestarle a la tienda. A la tienda solo le regresa X-Correlation-Id.
¿No te corre? ./verifica solucion prueba la nuestra, y estos dos comandos te dicen en qué son distintas:
diff mio/orden-router/orden-router.camel.yaml solucion/orden-router/orden-router.camel.yaml
diff mio/int-rest/int-rest.camel.yaml solucion/int-rest/int-rest.camel.yaml
| Lo que ves | Qué haces |
|---|---|
int-rest no anotó el hilo |
Falta el paso 1 en el router, o el paso 2 quedó debajo del removeHeaders (paso 6) |
La API no recibió el hilo con todo lo demás en verde |
Falta el paso 3: int-rest lo tiene, pero no se lo pasa a la API |
El puerto 8080 está ocupado |
Quedaron los servicios arriba: DONDE=mio docker compose -f compose.yaml down |
Ejercicio: encuentra una orden
Levanta tu versión, manda tres órdenes (la 1001, la 1003 y otra vez la 1001), cada una sin X-Correlation-Id, y
anota el id que te devolvió cada una. Después, solo con el id de la segunda, contesta: ¿qué orden era, qué le
contestó la API y cuánto tardó desde que llegó al router hasta que la API respondió? Pista: cada renglón del log
empieza con la hora.
Por qué se hizo así
Lo que decidimos en esta lección, con lo que descartamos y qué nos haría cambiar de idea:
- CloudEvents en modo binario como sobre
- El hilo de correlación viaja con la orden, pero no sale de casa
Repaso
- ¿Qué diferencia hay entre
ce-idyce-correlationid? - Si la tienda no manda id, ¿quién lo pone y de qué forma?
- ¿Por qué int-rest guarda el hilo en una variable antes del
removeHeaders? - ¿Qué escribió la API cuando el hilo no le llegó, y por qué es peor que un error?
- ¿Para qué le sirve a la tienda recibir su id de vuelta?
Siguiente: en la lección 10 el router deja de mandarle la orden solo a int-rest: la manda a la vez a los tres destinos, y el mismo hilo tiene que llegar a la API, al ERP y al socio.
¿Prefiere correo? Escríbanos a hola@habil.mx