Apache-2.0
Rust · Tiempo real

mtwRequest

Un solo runtime Rust para WebSocket, HTTP y agentes IA.

Dejá de pegar tres servicios. Conexión, auth y estado compartidos — en un solo core.

Tres servicios en uno

La mayoría de los stacks pegan un broker pub/sub, un framework REST y un runtime de agentes — tres deploys, tres superficies de auth, tres modos de falla. mtwRequest colapsa los tres en un único core Rust.

Tres servicios separados
  • →NATS / Centrifugo para pub/sub
  • →Express / Fastify para HTTP
  • →Framework de agentes aparte para IA
  • →Tres deploys, tres superficies de auth
  • →Pegamento manual para sincronizar estado
Un solo core mtwRequest
  • ✓WebSocket + HTTP comparten conexión
  • ✓Agentes IA como módulos de primer nivel
  • ✓Una auth, un estado, un tracing
  • ✓Marketplace de módulos para componer
  • ✓Apache-2.0 — forkealo, mandalo a prod

Benchmarks head-to-head

Same-host, Docker 2 CPU / 2 GB por competidor, payload 128 B, HdrHistogram 3 cifras significativas.

Runner reproducible en bench-suite/.

Escenario mtwRequest vs líderes
🥈 Fanout 100 subs · p50 17.53 ms empate con NATS (16.97 ms)
🥇 Fanout 1000 subs · p50 197.53 ms 1.5× más rápido que NATS (299.63 ms)
🥇 Fanout 1000 subs · p99 367.79 ms mejor que NATS (554.70 ms)
🥈 Echo RTT · p50 62.2 µs empate con NATS (Δ 3.8 µs)
🥇 Connect storm · rate 50.9 k conn/s 2.7× más que NATS

mtwRequest queda 🥇 o 🥈 en cada métrica de latencia — y además ofrece HTTP, agentes IA, auth, trading y MCP en el mismo core.

Donde gana NATS

NATS sigue liderando en throughput crudo de broadcast en fanout-1000: 2.66 G/s vs los 506 M/s de mtwRequest (5.2× más). Es un techo estructural de TCP-sin-WebSocket — un trade-off consciente que hacemos para mantener el protocolo compatible con browsers. Si tu hot path es server-to-server, NATS es la elección correcta.

Gráficos del último run

Distribuciones sobre mtw, nats, centrifugo y socketio. Generados por el bench-suite — mismo artefacto que obtendrías localmente.

Latencia fanout

1 publisher → N subscribers · 100 y 1000 subs · payload 128 B

SVG
Gráfico de benchmark: Latencia fanout

Echo round-trip

Requester → echo bot → requester · 2.000 round-trips

SVG
Gráfico de benchmark: Echo round-trip

Connect storm

500 conexiones concurrentes · latencia por conexión + tasa

SVG
Gráfico de benchmark: Connect storm

Corré bench-suite/run.sh en el repo para reproducirlo en tu propio host.

Qué trae el core

No es un broker pegado con cinta. Es un único runtime con baterías incluidas.

Un solo runtime, no tres

pub/sub + REST + agentes IA comparten conexión, auth y estado. Dejá de pegar NATS + Express + un framework de agentes aparte.

Wire format dual

JSON por defecto para interop. MsgPack opt-in vía subprotocolo mtw.msgpack.v1 — distribución p99 4.7× más estrecha, ~50% menos bytes.

Módulos componibles

Trait MtwModule con lifecycle hooks, middleware con prioridad, canales pub/sub con glob matching e historial. Marketplace para instalar.

Observabilidad incluida

Tracing estructurado, healthchecks por módulo, métricas HdrHistogram en el bench-suite. El cableado de producción viene en el core.

Bindings multilenguaje

Bindings nativos para Node.js, Python y PHP. Browser vía WebAssembly. Mismo wire protocol en todos los clientes.

Pub/sub con glob + historial

Suscribite con patrones tipo orders.eu.*. Los canales tienen historial reproducible: nuevos suscriptores pueden ponerse al día.

Dos vistas del mismo runtime

Suscribite desde un browser. Componé un módulo del lado servidor. Misma conexión, misma auth.

Browser WebSocket + subprotocolo MsgPack
client.ts
const ws = new WebSocket('wss://api.example.com/mtw', 'mtw.msgpack.v1');

ws.onopen = () => {
  ws.send(JSON.stringify({
    "type": "subscribe",
    "channel": "orders.eu.*"
  }));
};

ws.onmessage = (msg) => {
  const evt = JSON.parse(msg.data);
  console.log('event', evt.channel, evt.payload);
};
Rust Trait MtwModule
price_feed.rs
use mtw_request::{MtwModule, Context, Result};

pub struct PriceFeed;

#[async_trait]
impl MtwModule for PriceFeed {
  fn name(&self) -> &str { "price-feed" }

  async fn on_start(&self, ctx: &Context) -> Result<()> {
    ctx.subscribe("ticker.*").await?;
    Ok(())
  }

  async fn on_message(&self, ctx: &Context, m: Message) -> Result<()> {
    ctx.publish("alerts", m.payload).await
  }
}

Bindings para cada cliente

Mismo wire protocol. Misma auth. Distinto lenguaje en el borde.

Node.js

Disponible

Python

Disponible

PHP

Disponible

Browser (WASM)

Roadmap

Cuándo mtwRequest, cuándo no

Defaults honestos. Elegí la herramienta correcta para tu hot path.

Elegí mtwRequest si…

  • • Necesitás WebSocket + HTTP + agentes IA en un solo runtime
  • • La latencia de cola en fanout hacia browsers es tu SLA
  • • Querés composición por módulos, no un broker congelado
  • • Querés auth, MCP y trading en el mismo core (en roadmap / shipped)

Elegí NATS si…

  • • Tu hot path es server-to-server por TCP, sin browsers
  • • Necesitás 1 G/s+ de throughput crudo de broadcast
  • • Ya operás un cluster JetStream que te funciona
  • • No necesitás HTTP ni agentes IA en el mismo proceso

Construido sobre

Cimientos aburridos. Comportamiento predecible.

Rust Tokio tokio-tungstenite ArcSwap MsgPack HdrHistogram WebAssembly Apache-2.0

Preguntas frecuentes

¿En qué se diferencia mtwRequest de NATS o Centrifugo?
La mayoría de las alternativas son motores pub/sub estrechos. mtwRequest incluye WebSocket, HTTP y agentes IA en el mismo core Rust, con conexión, auth y estado compartidos — sin pegar tres servicios. NATS sigue ganando en throughput crudo de broadcast (1.20 G/s vs 124 M/s en fanout-500); es un techo estructural de TCP-sin-WS y un trade-off consciente para mantener compatibilidad con browsers.
¿Los benchmarks son reproducibles?
Sí. Same-host, Docker 2 CPU / 2 GB por competidor, payload 128 B, HdrHistogram a 3 cifras significativas. El runner está en bench-suite/ del repo. No extrapolar a producción distribuida — la suite es para comparación head-to-head.
¿JSON o MsgPack? ¿Cuál uso?
JSON es el default para interop. Activá MsgPack vía subprotocolo mtw.msgpack.v1 cuando importa la cola: p50 baja 17.5% y la distribución p99 queda 4.7× más estrecha. El tamaño en wire es ~50% menor. Usalo cuando tenés SLA de cola.
¿Qué bindings de lenguaje hay?
Node.js, Python y PHP están shipped. El binding de browser compila el core a WebAssembly y está en el roadmap. Todos los bindings hablan el mismo wire protocol y autentican contra la misma conexión.
¿Hay marketplace de módulos?
Sí. El trait MtwModule, los lifecycle hooks y el sistema de middleware están shipped. El registry público está en el roadmap — ver ARCHITECTURE.md para el estado actual.
¿Licencia y soporte?
Apache-2.0. Código en GitHub: fastslack/mtwRequest. Soporte comercial disponible — agendá una consulta si querés ayuda en producción.

Reproducí el bench, forkeá el core

Apache-2.0. El runner está en el repo. Si querés ayuda en producción, agendá una consulta.