Módulo 5: Dependencias entre workflows
3. El grafo de dependencias
Descripción
Al terminar esta lección vas a poder dibujar el grafo de dependencias de un sistema de varios workflows: un diagrama donde cada caja es un workflow, cada flecha es una relación de "este depende de aquel", y cada flecha está anotada con su tipo —llamada síncrona, disparo asíncrono o evento— y con si transporta una lectura o un efecto. Con ese dibujo en la mano vas a poder hacer tres cosas que sin él son adivinanza: detectar ciclos (una pieza que termina dependiendo de sí misma), calcular el radio de explosión de un fallo (hasta dónde se propaga si una pieza se cae), y descubrir dependencias ocultas —piezas que no se llaman entre sí pero comparten un recurso y por eso se caen juntas—.
Esto importa porque el grafo es la herramienta más barata y más poderosa de todo el módulo. No requiere escribir código, se dibuja en cinco minutos, y la mitad de los bugs de coordinación que verías aparecer en producción son visibles a simple vista en él: un ciclo salta a la vista, un punto que si se cae deja a tres piezas sin servicio se ve de un vistazo, una dependencia oculta se descubre en cuanto anotas qué recurso externo toca cada pieza. Los sistemas que explotan en producción casi nunca explotan por un nodo mal configurado; explotan por una relación entre workflows que nadie dibujó y por eso nadie vio.
Conexión con el módulo: la lección 2 te dio los dos tipos de flecha —orquestación (llamada que espera) y coreografía (evento que reacciona)—. Esta lección junta todas las flechas en un solo dibujo y te enseña a leerlo. Es la herramienta de diagnóstico que vas a usar en el resto del módulo: en la lección 4 el grafo te muestra dónde repartes y vuelves a juntar trabajo, en la lección 5 dónde se acumulan los eventos, en la lección 6 dónde conviene meter un outbox, y en el proyecto de la lección 8 el grafo es, literalmente, la mitad del entregable. Aprender a dibujarlo bien aquí paga en cada lección que sigue.
Un mapa de "quién se cae si esto se cae"
Piensa en el tablero eléctrico de una casa. Es una fila de interruptores, y cada uno alimenta una parte: uno la cocina, uno las recámaras, uno el garaje. La mayoría de la gente no lo entiende hasta el día que se va la luz en media casa y descubre, tanteando, que el refrigerador y el microondas estaban en el mismo circuito, así que cuando saltó el del microondas, el refri también se apagó y se echó a perder la comida. Nadie había dibujado nunca qué alimentaba cada interruptor. La dependencia existía —el refri dependía del mismo circuito que el microondas— pero era invisible hasta que causó un daño.
Un electricista serio no trabaja así. Antes de tocar nada, tiene —o dibuja— el diagrama del tablero: qué interruptor alimenta qué, y qué cosas cuelgan del mismo circuito. Con ese diagrama, la pregunta "si apago este interruptor, ¿qué se queda sin luz?" tiene respuesta antes de apagarlo. Y la pregunta "si este circuito se sobrecarga, ¿qué se cae con él?" también.
El grafo de dependencias es ese diagrama, para tu sistema de workflows. Responde la misma pregunta: si esta pieza se cae, ¿qué se cae con ella? Y su valor es el mismo: convierte una dependencia invisible —que solo descubrirías el día del apagón— en una línea dibujada que puedes ver, razonar y arreglar antes de que cause daño. Un sistema sin su grafo dibujado es una casa sin diagrama del tablero: funciona hasta que un día se va la luz en media casa y nadie sabe por qué.
Anatomía del grafo: cajas, flechas y anotaciones
Un grafo de dependencias tiene tres ingredientes. Vamos uno por uno, porque la potencia está en las anotaciones, no en las cajas.
Las cajas son los workflows. Cada workflow del sistema es una caja con su nombre. En Cumbre: order-triage, check-credit, issue-refund, inventory-sync. Simple.
Las flechas son las dependencias. Una flecha de A a B significa "A depende de B": A necesita que B haga algo para que A haga su trabajo. La dirección importa y confunde al principio, así que fíjala bien: la flecha apunta hacia la pieza de la que se depende. order-triage → check-credit significa "order-triage depende de check-credit", es decir, order-triage lo llama y necesita su respuesta. La punta de la flecha señala al que hace el trabajo pedido.
Las anotaciones son lo que hace útil el grafo. Una flecha pelada te dice que hay una relación, pero no cómo es. Dos anotaciones cambian todo:
- El tipo de relación, que viene de la lección 2: ¿es una llamada síncrona (orquestación con espera: A llama a B y se queda esperando su resultado)? ¿Una llamada asíncrona (A dispara a B pero no espera)? ¿O un evento (coreografía: A emite un evento y B reacciona)? Cada tipo se propaga distinto, como vas a ver.
- Qué transporta, que viene de toda la guía: ¿la pieza de la que se depende es una lectura (segura de repetir, como
check-credit) o un efecto (peligrosa de repetir, comoissue-refundeinventory-sync)?
Vamos a usar una notación simple para las flechas. La escribo así para que la puedas dibujar a mano:
A ──(sync)──▶ B A llama a B y espera su resultado (orquestación síncrona)
A ┈┈(async)┈▶ B A dispara a B y sigue sin esperar (orquestación asíncrona)
A ~~(event)~▶ B A emite un evento; B reacciona (coreografía)
Y marcamos cada caja de destino con [L] si es una lectura o [E] si es un efecto.
El grafo de Cumbre, dibujado
Tomemos el sistema orquestado de la lección 2 y dibujémoslo entero. order-triage recibe el pedido, consulta el crédito, y según el resultado descuenta inventario o emite un reembolso. Además emite un evento "order.created" que dispara la notificación de ventas en coreografía.
order-triage
(recibe y coordina)
│
┌─────────────────────┼──────────────────────────┐
│ (sync) │ (sync, si no hay crédito) │ (event)
▼ ▼ ▼
check-credit issue-refund sales-notifier
[L] [E] [E]
(lee crédito) (mueve dinero) (manda aviso)
│
│ (sync, si hay crédito)
▼
inventory-sync
[E]
(cambia stock)
Ese dibujo, con sus anotaciones, ya te dice mucho más que "hay cuatro workflows". Léelo:
order-triagedepende decheck-creditcon una llamada síncrona a una lectura. Espera el resultado para decidir. Comocheck-credites una lectura, si se llama dos veces no hay daño de duplicado —pero sí hay riesgo de cascada, porqueorder-triageespera—.order-triagedepende deissue-refundy deinventory-synccon llamadas síncronas a efectos. Estas son las flechas peligrosas: transportan operaciones que al repetirse hacen daño.order-triagedepende desales-notifiercon un evento. Desacoplado: sisales-notifierse cae,order-triageno se entera ni se bloquea.
Fíjate en cómo las anotaciones te orientan la atención. Las dos flechas hacia efectos, síncronas, son donde vive el riesgo del módulo. La flecha de evento es la más tranquila. La flecha hacia la lectura es tranquila en cuanto a duplicados pero es la sospechosa de cascada. Un grafo bien anotado es un mapa de dónde mirar.
Dependencias directas y transitivas
Hay una sutileza que el grafo hace visible y que a ojo se pierde: las dependencias transitivas.
Una dependencia directa es una flecha: order-triage → check-credit. Una dependencia transitiva es una cadena: si check-credit, a su vez, dependiera de un workflow credit-bureau-lookup que consulta a un buró de crédito externo, entonces order-triage dependería transitivamente de credit-bureau-lookup, aunque no lo llame directamente.
order-triage ──(sync)──▶ check-credit ──(sync)──▶ credit-bureau-lookup [L]
¿Por qué importa? Porque el radio de explosión sigue las cadenas transitivas, no solo las flechas directas. Si credit-bureau-lookup se cae, check-credit no puede responder, y order-triage —que espera a check-credit— tampoco avanza. El buró de crédito, con el que order-triage no habla directamente y probablemente ni sabe que existe, puede frenar la recepción de pedidos. Esa es la clase de sorpresa que el grafo evita: dibujas la cadena completa y ves, hasta el final, de qué dependes de verdad.
La regla práctica: tu sistema depende de todo lo que está río abajo de tus flechas, no solo de lo que tocas directamente. El grafo transitivo —el que sigue cada cadena hasta el final— es el que te dice tu superficie real de fallo.
Ciclos: la pieza que depende de sí misma
Un ciclo es cuando sigues las flechas y vuelves al punto de partida: A depende de B, B depende de C, C depende de A. En un grafo de dependencias, un ciclo casi siempre es un problema, y a veces es un desastre.
Piénsalo con dos personas que se ceden el paso en una puerta con exagerada cortesía. "Pasa tú." "No, pasa tú." "Insisto, tú primero." Si ninguna rompe la regla de ceder, se quedan ahí para siempre. Cada una está esperando a la otra; nadie avanza. Eso es un ciclo síncrono: un abrazo mortal donde cada pieza espera a la que la está esperando.
En Cumbre, un ciclo podría colarse así, sin mala intención. Supón que alguien decide que inventory-sync, cuando detecta que un producto quedó en stock negativo por un error, debe disparar issue-refund para devolver el dinero de las unidades que no había. Y que issue-refund, para saber cuánto reembolsar, llama a inventory-sync para consultar el stock. Dibujado:
issue-refund ──(sync)──▶ inventory-sync ──(sync)──▶ issue-refund ──▶ ...
Si las dos llamadas son síncronas y esperan, tienes el abrazo mortal: issue-refund espera a inventory-sync, que espera a issue-refund, que espera... Nadie termina. Y si en vez de esperar, cada una dispara a la otra, tienes algo peor: un bucle que se auto-alimenta, emitiendo reembolsos y sincronizando inventario en cadena, sin fin, hasta que algo revienta o hasta que emitiste cien reembolsos.
Cómo se detecta un ciclo. A ojo, en un sistema chico, se ve: dibujas las flechas y notas que vuelves a una caja por la que ya pasaste. En un sistema más grande, la forma más confiable es exportar los workflows a JSON y seguir las llamadas —cada Execute Sub-workflow te dice a quién llama—, o simplemente construir el grafo pieza por pieza y buscar si alguna cadena se muerde la cola. La regla es dura y vale la pena grabarla: en un grafo de dependencias sano, si empiezas en cualquier caja y sigues las flechas, nunca vuelves a esa caja. A eso se le llama un grafo sin ciclos, o acíclico.
Cómo se rompe un ciclo. Casi siempre, el ciclo es señal de que dos piezas están demasiado entrelazadas y una de las dos relaciones no debería existir o debería ser un evento en vez de una llamada. En el ejemplo: en vez de que issue-refund llame a inventory-sync para consultar el stock, el stock debería viajar en el encargo —order-triage u otro director le pasa a issue-refund cuánto reembolsar—, cortando esa flecha. Recuerda además la regla que viste en la guía de chatbots para agentes: los trabajadores no se delegan entre sí directamente, justamente para que el grafo no tenga ciclos. La misma disciplina aplica a los workflows.
Dependencias ocultas: piezas que se caen juntas sin llamarse
Aquí está la clase de dependencia que más daño hace, porque no es una flecha. Son dos piezas que, en el grafo de llamadas, no se tocan —ninguna llama a la otra— y sin embargo se caen juntas, porque comparten un recurso.
Volvamos al tablero eléctrico: el refrigerador y el microondas no se "llaman" entre sí, pero comparten un circuito, así que cuando el circuito salta, los dos se apagan. En un sistema de workflows, los recursos compartidos que crean dependencias ocultas son varios:
- Una API externa compartida. En Cumbre, tanto el cobro original de un pedido como
issue-refundusan la misma pasarela de pago. En el grafo de llamadas no hay flecha entre ellos. Pero si la pasarela se cae, o si alcanzas su límite de peticiones por minuto, los dos fallan a la vez. Comparten la pasarela como el refri y el microondas comparten el circuito. - Una base de datos compartida. Los cuatro workflows de Cumbre leen y escriben el mismo ledger de Postgres. Si esa base se satura o se cae, los cuatro se ven afectados, aunque no se llamen entre sí.
- Una credencial o una cuota compartida. Si
check-credity otro workflow usan la misma clave de API de un servicio con un límite mensual, uno puede agotar la cuota y dejar al otro sin servicio, sin que exista ninguna llamada entre ellos. - El mismo worker. En una instancia sin queue mode, todos los workflows comparten el mismo proceso. Un workflow que consume todo el CPU afecta a los demás. La lección 5 vuelve sobre esto.
Las dependencias ocultas se dibujan aparte, porque no son flechas de llamada. Una forma útil es anotar, debajo de cada caja, qué recursos externos toca, y luego marcar los que se repiten:
order-triage → pasarela de pago (cobro), ledger Postgres, modelo de IA
check-credit → API del buró de crédito, ledger Postgres
issue-refund → pasarela de pago (reembolso), ledger Postgres
inventory-sync → sistema de bodega, ledger Postgres
Recursos compartidos (dependencias ocultas):
⚠ pasarela de pago → order-triage + issue-refund se caen juntos si la pasarela cae
⚠ ledger Postgres → los cuatro dependen de él
Ese pequeño inventario de recursos, hecho una vez, te ahorra el apagón. La primera vez que la pasarela de pago tenga un mal día, ya sabrás —porque lo dibujaste— que van a fallar a la vez el cobro de pedidos nuevos y los reembolsos, y podrás explicarlo en vez de tantear.
Ejemplo trabajado: el radio de explosión de dos fallos
El grafo cobra todo su valor cuando lo usas para responder "¿qué se cae si esto se cae?". Vamos a calcularlo para dos fallos concretos de Cumbre, usando el grafo de arriba.
Fallo 1 — se cae check-credit. El sistema del buró de crédito no responde, así que check-credit no puede devolver su resultado.
Qué esperar. Seguimos las flechas hacia atrás, hacia quién depende de check-credit. La única flecha que llega a check-credit viene de order-triage, y es una llamada síncrona: order-triage está esperando el resultado. Como no llega, order-triage se queda bloqueado —o falla, si tiene un tiempo de espera configurado— en ese punto. Y como order-triage no avanza, tampoco llega a llamar a inventory-sync ni a issue-refund: la cadena entera río abajo de la decisión de crédito queda sin ejecutarse. El radio de explosión es: order-triage (bloqueado) y, por transitividad, todo lo que order-triage haría después. En cambio, sales-notifier, que cuelga de un evento independiente, no se ve afectado: reacciona a "order.created", que se emitió antes de la cadena de crédito. Ahí ves, en el grafo, la diferencia entre una flecha síncrona (propaga el fallo) y una de evento (lo contiene).
Fallo 2 — se cae la pasarela de pago. Este es el interesante, porque es una dependencia oculta, no una flecha.
Qué esperar. La pasarela no aparece como una caja en el grafo de llamadas, así que si solo miraras las flechas, dirías "no afecta nada". Pero en tu inventario de recursos anotaste que dos piezas la usan: el cobro dentro de order-triage y issue-refund. Cuando la pasarela cae, las dos fallan a la vez: los pedidos nuevos no se pueden cobrar y los reembolsos no se pueden emitir. Dos síntomas que parecen no tener relación —"no entran pedidos" y "no salen reembolsos"— tienen la misma causa raíz, y solo lo sabes porque dibujaste la dependencia oculta. Sin ese inventario, habrías perseguido dos bugs distintos durante una hora antes de darte cuenta de que era uno solo.
La lección de los dos fallos: el radio de explosión se sigue por las flechas síncronas hacia atrás (quién me espera) y por los recursos compartidos (quién comparte mi circuito). Las flechas de evento cortan la propagación. Y las dependencias ocultas solo se ven si las anotaste. Un grafo que solo tiene flechas de llamada está a medio dibujar.
Cómo construir el grafo de un sistema real, paso a paso
Cuando te toque hacerlo con un sistema que no diseñaste tú —el caso más común en un trabajo real—, este es el procedimiento:
- Lista los workflows. Una caja por cada uno. En n8n, la lista de workflows de tu instancia es el punto de partida.
- Encuentra las flechas de llamada. Abre cada workflow y busca los nodos
Execute Sub-workflow: cada uno es una flecha hacia el workflow que llama. Anota si tieneWait for Sub-Workflow Completionactivado (síncrona) o no (asíncrona). - Encuentra las flechas de evento. Busca los workflows que emiten eventos —un
HTTP Requesthacia el webhook de otro, o una escritura en una tabla de eventos— y los que los reciben —unWebhooko unSchedule Triggerque consulta esa tabla—. Cada par emisor-receptor es una flecha de evento. - Anota lecturas y efectos. Para cada caja de destino, marca
[L]o[E]según si su trabajo es una lectura o un efecto. Esto lo sabes de la auditoría del Módulo 1. - Inventaria los recursos externos. Debajo de cada caja, lista las APIs, bases de datos y credenciales que toca. Marca las que se repiten: esas son tus dependencias ocultas.
- Busca ciclos. Empieza en cualquier caja, sigue las flechas, y verifica que nunca vuelves a una caja por la que ya pasaste.
Al terminar tienes un dibujo que responde, sin ejecutar nada, las preguntas que importan: qué se cae si cae cada pieza, dónde hay un abrazo mortal esperando a ocurrir, y qué piezas comparten un circuito. Ese dibujo es el entregable de la mitad de la lección 8, y es lo primero que un dueño de sistema hace cuando hereda una automatización que no entiende.
Errores comunes
Dibujar solo las flechas de llamada y olvidar los recursos compartidos (conceptual). Qué pasa: alguien hace un grafo prolijo con todas las flechas de Execute Sub-workflow, concluye "no hay dependencias entre order-triage e issue-refund más que a través del director", y el día que la pasarela de pago se cae, los dos fallan a la vez y nadie lo había previsto. Por qué pasa: las flechas de llamada son visibles —hay un nodo que las representa— y los recursos compartidos no; hay que ir a buscarlos a propósito. Cómo detectarlo: si tu grafo no tiene una lista de recursos externos por caja, está a medio hacer. Cómo corregirlo: haz siempre el paso 5 del procedimiento —inventariar los recursos externos y marcar los repetidos—; las dependencias ocultas causan los fallos más confusos justamente porque no se ven en las flechas.
Confundir la dirección de la flecha (práctico). Qué pasa: alguien dibuja check-credit → order-triage porque "check-credit le da el resultado a order-triage", y luego calcula mal el radio de explosión, porque siguió las flechas al revés. Por qué pasa: la dirección de una dependencia es contraintuitiva —el dato viaja de check-credit a order-triage, pero la dependencia va al revés, porque es order-triage quien necesita a check-credit—. Cómo detectarlo: pregúntate "¿cuál de los dos no puede hacer su trabajo sin el otro?". Ese es el que depende, y de él sale la flecha. Cómo corregirlo: fija la convención de una vez —la flecha apunta hacia la pieza de la que se depende, la que hace el trabajo pedido— y verifícala leyendo la flecha en voz alta: "order-triage depende de check-credit", flecha de order-triage a check-credit.
Ignorar las dependencias transitivas (conceptual). Qué pasa: alguien mapea las flechas directas de su sistema, se siente cubierto, y no nota que un workflow tres saltos río abajo —al que su director nunca llama directamente— es un buró de crédito externo lento que puede frenar todo. Por qué pasa: es natural detenerse en "a quién llamo yo" y no seguir la cadena hasta el final. Cómo detectarlo: por cada flecha síncrona, pregúntate "¿y este de quién depende, a su vez?", y sigue hasta llegar a piezas que no llaman a nadie. Cómo corregirlo: dibuja el grafo completo, transitivo, hasta las hojas; tu superficie real de fallo incluye todo lo que está río abajo, no solo lo que tocas directamente.
No revisar si hay ciclos hasta que uno explota (práctico). Qué pasa: se van agregando flechas al sistema con el tiempo —"que este también llame a este"— y en algún momento se cierra un ciclo sin que nadie lo note, hasta el día que dos workflows se quedan esperándose o entran en un bucle que emite reembolsos sin parar. Por qué pasa: cada flecha se agrega por una buena razón local, y el ciclo emerge de la suma, que nadie mira completa. Cómo detectarlo: cada vez que agregues una flecha nueva, recorre el grafo desde la caja de destino siguiendo las flechas y verifica que no puedas volver a la caja de origen. Cómo corregirlo: mantén el grafo acíclico como una regla de diseño; si una flecha nueva cerraría un ciclo, casi siempre significa que esa relación debería ser un evento, o que un dato que se está pidiendo en una llamada debería viajar en el encargo.
Ejercicios
Ejercicio 1 — Dibuja y anota. Cumbre agrega un workflow nuevo, restock-alert, que se dispara cuando inventory-sync deja un producto por debajo de su mínimo: inventory-sync emite un evento "stock.low" y restock-alert reacciona mandando un correo al proveedor. restock-alert es un efecto (manda un correo). Dibuja el grafo completo de Cumbre incluyendo esta pieza, con la notación de tipo de flecha y [L]/[E], y di de qué depende transitivamente order-triage que antes no.
Ver solución
order-triage
│
┌─────────────────────┼──────────────────────────┐
│ (sync) │ (sync, si no crédito) │ (event)
▼ ▼ ▼
check-credit [L] issue-refund [E] sales-notifier [E]
│
│ (sync, si hay crédito)
▼
inventory-sync [E]
│
│ (event: "stock.low")
▼
restock-alert [E]
Antes, order-triage dependía transitivamente de check-credit, issue-refund e inventory-sync. Ahora, como inventory-sync emite un evento que dispara restock-alert, hay una nueva cadena. Pero fíjate en el detalle importante: esa nueva flecha es un evento, no una llamada síncrona. Así que order-triage no depende de restock-alert de forma que pueda bloquearlo: si restock-alert se cae, inventory-sync ya emitió su evento y siguió, y order-triage ni se entera. La cadena existe en el grafo, pero la flecha de evento la desacopla. Por eso anotar el tipo de flecha no es decorativo: cambia por completo cómo se propaga un fallo por esa cadena.
Por qué funciona: distinguiste una dependencia transitiva que existe (hay un camino de order-triage a restock-alert) de una propagación de fallo que no existe (el evento corta la cadena). Esa distinción —hay flecha, pero no propaga— es exactamente lo que las anotaciones te dejan ver.
Ejercicio 2 — Encuentra el ciclo. Te pasan la descripción de un sistema: A llama de forma síncrona a B; B, para completar su trabajo, llama de forma síncrona a C; C, en cierto caso, llama de forma síncrona a A. Dibuja el grafo, di si hay un ciclo, qué pasa cuando se dispara ese "cierto caso", y cómo lo romperías.
Ver solución
A ──(sync)──▶ B ──(sync)──▶ C ──(sync, en cierto caso)──▶ A ──▶ ...
Sí hay un ciclo: empezando en A, sigues las flechas y vuelves a A. Es un ciclo síncrono, así que es un abrazo mortal potencial. Cuando se dispara ese "cierto caso", C llama a A, pero A todavía está esperando —río arriba, en la primera llamada— el resultado de B, que espera a C, que ahora espera a A. Los tres se quedan bloqueados esperándose en círculo. Nadie termina. En la práctica, esto suele manifestarse como ejecuciones que se cuelgan, se acumulan y eventualmente agotan los recursos de la instancia, o como un error de "profundidad de llamada excedida" si el motor lo detecta.
Cómo romperlo: hay que cortar una de las tres flechas del ciclo, y casi siempre la culpable es la última, la de C → A, porque cerrar el círculo rara vez es lo que de verdad se necesita. Las opciones habituales: convertir esa llamada en un evento (C emite un evento y A, u otra pieza, reacciona en una ejecución nueva, no dentro de la que ya está esperando), o rediseñar para que el dato que C le está pidiendo a A viaje en el encargo desde el principio, eliminando la necesidad de la llamada. La regla de fondo: mantén el grafo acíclico.
Por qué funciona: identificaste el ciclo siguiendo las flechas hasta volver al inicio, explicaste el bloqueo en términos de "cada uno espera al que lo espera", y aplicaste la cura estándar —cortar la flecha que cierra el círculo, convirtiéndola en evento o eliminándola—. Ese es el manejo completo de un ciclo.
Ejercicio 3 — El radio de explosión de un recurso oculto. En Cumbre, resulta que check-credit y un nuevo workflow fraud-check usan el mismo servicio de terceros para verificar identidad, y ese servicio tiene un límite de 100 peticiones por minuto compartido entre los dos. Un lunes de mucho volumen, fraud-check consume él solo las 100 peticiones. Describe qué le pasa a check-credit, cómo se vería este problema en el grafo, y por qué es difícil de diagnosticar sin haber inventariado los recursos.
Ver solución
Qué le pasa a check-credit: como fraud-check agotó las 100 peticiones por minuto del servicio compartido, las llamadas de check-credit a ese mismo servicio empiezan a ser rechazadas por límite de tasa. check-credit no puede completar su trabajo, así que devuelve error o se atrasa. Y como order-triage lo llama de forma síncrona y espera, la cadena de pedidos se frena —una cascada—. El detalle cruel: check-credit está perfectamente bien; el problema lo causó fraud-check, con el que check-credit no tiene ninguna flecha de llamada.
Cómo se vería en el grafo: no se vería en las flechas de llamada, porque no hay ninguna entre check-credit y fraud-check. Se vería solo en el inventario de recursos, si lo hiciste: los dos tendrían anotado "servicio de verificación de identidad (límite 100/min compartido)", y ese recurso repetido es la dependencia oculta. Marcado así:
check-credit → servicio de verificación de identidad, ledger
fraud-check → servicio de verificación de identidad, ledger
⚠ servicio de verificación (100/min compartido)
→ fraud-check puede agotar la cuota y dejar sin servicio a check-credit
Por qué es difícil de diagnosticar sin el inventario: los síntomas apuntan a check-credit ("los pedidos se frenan en la consulta de crédito"), pero la causa está en fraud-check, una pieza que no aparece en esa parte del grafo. Sin haber anotado el recurso compartido, buscarías el problema en check-credit y en el servicio de crédito, y no lo encontrarías, porque el culpable es un vecino que comparte una cuota invisible.
Por qué funciona: este es el caso más traicionero de dependencia —una cuota compartida— y lo resolviste con la única herramienta que lo hace visible: el inventario de recursos con los límites anotados. Es la razón por la que el paso 5 del procedimiento no es opcional.
Resumen y siguiente paso
En esta lección aprendiste a dibujar el grafo de dependencias de un sistema de varios workflows: cajas para los workflows, flechas para las dependencias —apuntando hacia la pieza de la que se depende—, y dos anotaciones que lo hacen útil: el tipo de flecha (síncrona, asíncrona o evento) y qué transporta (lectura [L] o efecto [E]). Con ese dibujo puedes hacer tres cosas que sin él son adivinanza: detectar ciclos —recorriendo las flechas y verificando que nunca vuelves a una caja, la marca de un grafo sano—, calcular el radio de explosión de un fallo —siguiendo las flechas síncronas hacia atrás y los recursos compartidos—, y descubrir dependencias ocultas —piezas que no se llaman pero comparten una API, una base de datos o una cuota, y por eso se caen juntas—. Viste que las flechas de evento cortan la propagación de fallos, que tu sistema depende de todo lo que está río abajo (transitividad), y que un grafo sin su inventario de recursos está a medio dibujar.
Antes de avanzar a la lección 4 deberías poder: dibujar el grafo de Cumbre con sus anotaciones de memoria; explicar por qué una flecha síncrona propaga un fallo y una de evento no; y describir cómo una dependencia oculta —dos piezas que comparten un recurso— causa que se caigan juntas sin tener ninguna flecha entre sí.
Ahora que sabes leer el grafo, la lección 4 se mete en una forma concreta de flecha que aparece cuando un workflow reparte trabajo entre varios: el fan-out —un flujo dispara N sub-ejecuciones— y el fan-in —volver a juntar sus resultados—. Vas a ver el reto que esto tiene en n8n, cómo el nodo Merge junta lo que se repartió, y el peligro específico del reintento parcial: cuando de N ramas, unas terminaron y otras no, y reintentar vuelve a ejecutar las que ya estaban listas. Y vas a ver cómo el ledger del Módulo 4 —el pizarrón compartido— es justo lo que cubre ese hueco.
Recursos
- Sub-workflows — n8n Docs — cómo un sistema se compone de varios workflows que se llaman entre sí; las llamadas que dibujas como flechas nacen de estos nodos.
- Execute Sub-workflow node — n8n Docs — cada nodo de estos es una flecha del grafo; su opción
Wait for Sub-Workflow Completiondecide si la flecha es síncrona o asíncrona. - Export and import workflows — n8n Docs — cómo exportar un workflow a JSON para leer sus conexiones y sus llamadas cuando construyes el grafo de un sistema que no diseñaste tú.
- Error handling — n8n Docs — el manejo de errores que determina qué pasa exactamente cuando una pieza río abajo falla; el radio de explosión depende de cómo esté configurado esto, tema que profundiza el Módulo 6.