📐 Arquitectura — Caso 11: 💧 Elixir → 🌉 n8n → 🔴 Erlang (Cowboy) + Mnesia#
Emisor Elixir que reenvía posts vencidos a n8n; el receptor Erlang/Cowboy los persiste en Mnesia, la BD nativa de la BEAM embebida en el runtime. Demuestra el modelo de actores, la supervisión OTP y el patrón "let it crash".
🧭 Ficha técnica#
| Atributo | Valor |
|---|---|
| ID | 11 |
| Origen | Elixir — origin/lib/publisher.ex |
| Puente | n8n — case-11-elixir-to-erlang.json |
| Destino | Erlang/Cowboy 2.12 (release OTP) — dest/src/social_bot_dest_app.erl |
| Persistencia | Mnesia (ram_copies, embebida) |
| Puerto (dashboard) | http://localhost:8091 |
| Perfil Docker | case11 |
| Guardrails | Fingerprint · Circuit breaker · Idempotencia · HTTP con reintentos · DLQ |
🗺️ Diagrama de arquitectura#
diagrama mermaid
%%{init: {'theme':'base','themeVariables':{'fontSize':'26px','fontFamily':'Segoe UI, Arial, sans-serif'},'flowchart':{'useMaxWidth':true,'htmlLabels':false,'nodeSpacing':55,'rankSpacing':70,'padding':16,'diagramPadding':16}}%%
flowchart TB
subgraph ORIGIN["ORIGEN - Elixir"]
P["publisher.ex"]
end
subgraph BRIDGE["PUENTE - n8n + Guardrails"]
C(["Webhook"]) --> CB{"Circuit breaker"}
CB -->|abierto| STOP["Descarta"]
CB -->|cerrado| IDEM{"Idempotencia (fingerprint)"}
IDEM -->|duplicado| DISCARD["200 OK - descarta"]
IDEM -->|nuevo| FWD["HTTP forward + reintentos"]
FWD -.->|error| DLQ["Dead Letter Queue (/errors)"]
end
subgraph DEST["DESTINO - Erlang/Cowboy (BEAM)"]
FWD --> SUP["Supervisor OTP"]
SUP --> WH["webhook_handler"]
WH --> ST["store (transaccion)"]
ST --> DB[("Mnesia ram_copies")]
DB --> DASH["Dashboard :8091"]
end
P -->|POST JSON| C
classDef origin fill:#4B275F,stroke:#333,color:#fff
classDef bridge fill:#EA4B71,stroke:#333,color:#fff
classDef dest fill:#A90533,stroke:#333,color:#fff
classDef db fill:#6E4A7E,stroke:#333,color:#fff
class P origin
class C,CB,IDEM,FWD,DLQ,DISCARD,STOP bridge
class SUP,WH,ST,DASH dest
class DB db🔁 Diagrama de secuencia (ciclo de una publicación)#
diagrama mermaid
%%{init: {'theme':'base','themeVariables':{'fontSize':'24px','fontFamily':'Segoe UI, Arial, sans-serif'},'sequence':{'useMaxWidth':true,'actorFontSize':22,'messageFontSize':20,'noteFontSize':18,'actorMargin':90,'boxMargin':16,'width':180}}}%%
sequenceDiagram
autonumber
participant Ex as publisher.ex (Elixir)
participant N8N as n8n
participant Cow as Cowboy handler
participant Mn as Mnesia
Ex->>N8N: POST /webhook (post vencido)
N8N->>N8N: Circuit breaker + idempotencia
alt Duplicado o circuito abierto
N8N-->>Ex: 200 OK (descartado)
else Nuevo
N8N->>Cow: HTTP POST /webhook (reintentos x3)
Cow->>Cow: Proceso BEAM dedicado por request
Cow->>Mn: mnesia:transaction(write)
Mn-->>Cow: {atomic, ok}
Cow-->>N8N: 200 OK
N8N-->>Ex: 200 OK
end
Note over Cow,Mn: El dashboard :8091 lee via /logs (mnesia:transaction/read)🧩 Componentes#
💧 Origen — Elixir#
origin/lib/publisher.exleeposts.jsony reenvía los posts vencidos a n8n. Sin dependencias::httpcpara HTTP y el módulo:jsonde OTP 27.
🌉 Puente — n8n#
- Guardrails canónicos del laboratorio: fingerprint → circuit breaker → idempotencia → HTTP forward con reintentos → DLQ.
🔴 Destino — Erlang/Cowboy + Mnesia#
social_bot_dest_appinicializa Mnesia y levanta Cowboy;social_bot_dest_supes el árbol de supervisión OTP.webhook_handlerpersiste cada post en una transacción Mnesia;logs_handlersirve los últimos registros;dashboard_handlersirve el HTML desdepriv/.- Empaquetado como release OTP con ERTS embebido.
▶️ Cómo levantarlo#
bash
docker-compose --profile case11 up -d # receptor Erlang/Cowboy + Mnesia (sin BD externa)Dashboard: http://localhost:8091
🔗 Enlaces#
- 📄 README del caso
- 🗺️ Arquitectura global del laboratorio
- 🛡️ Guardrails de resiliencia
- 🧩 Índice de casos
Diagramas en Mermaid — se renderizan nativamente en GitHub. Parte de Social Bot Scheduler.