

Akagitsune
赤狐
A generic realtime WebSocket gateway built in Rust.
Pure transport — it relays, it does not interpret.
What It Is
A WebSocket relay that stays out of your way
Akagitsune is a generic realtime gateway — a piece of infrastructure, not a product. It connects sockets and moves bytes. What those bytes mean is entirely your decision.
Payload-Agnostic
The gateway forwards your data without touching it. Chat messages, game states, live dashboards, IoT telemetry — it all rides the same wire. The meaning is yours; the transport is ours.
Real-Time, Always
Built on asynchronous Rust with a lock-free hot path. Every message is serialized once — not once per receiver — then broadcast to all connected peers instantly.
Backpressure Over Breakage
When a slow client falls behind, Akagitsune drops its queued messages and warns it — rather than slowing down everyone else. The fast stay fast; the slow get a second chance.
Three Tasks, One Connection
Each connection runs a reader (ingest), a bridge (fanout), and a writer (flush). Bounded queues everywhere, no shared locks, reference-counted message clones. Clean, predictable, debuggable.
Get it running
Performance
One million, sustained
The target is a million deliveries a second inside a 10–20 ms p99 budget. All three traffic shapes clear it, and clear half again as much. Past that they part ways: fanout is the expensive one, and it breaks first.
Service p99 against offered load
Log scale, because the spread runs from 3 ms to 825 ms. The dashed rule is the 20 ms budget; the tinted band above it is out of spec.
- ingestmany senders, one topic
- mesheveryone talks to everyone
- fanoutone sender, every socket
Ingest stops at 1.5M because it was never run above it. The hollow marker at 2.78M is a separate exploratory shape, and the only point where delivery rather than latency is what gives out.
Every run, in full
Latency in milliseconds. Rows that miss the budget are dimmed. Scroll the table sideways for the rest of the columns.
| Offered load | Shape | Conns | p50 | p99 | Delivered | Against budget |
|---|---|---|---|---|---|---|
| 1,000,000 | ingest | 101 | 1.83 | 3.00 | 100% | within budget |
| 1,000,000 | mesh | 201 | 3.06 | 5.39 | 100% | within budget |
| 1,000,000 | fanout | 501 | 2.46 | 6.03 | 100% | within budget |
| 1,500,000 | ingest | 101 | 1.66 | 3.16 | 100% | within budget |
| 1,500,000 | mesh | 251 | 3.53 | 6.51 | 100% | within budget |
| 1,500,000 | fanout | 501 | 6.16 | 18.88 | 100% | within budget |
| 2,000,000 | mesh | 201 | 16.45 | 48.77 | 100% | over budget |
| 2,000,000 | fanout | 1001 | 42.88 | 193.02 | 100% | over budget |
| 2,782,322 | explore | 301 | 180.74 | 825.34 | 92.74% | delivery breaks |
Every number is from a single local run on Apple M4 Pro, 14 cores, release build, gateway and load generator on the same machine — not a production deployment. Latency is service latency: message arrival minus actual send, the more conservative of the two figures the harness records. The highest load every shape held inside the budget was 1,500,000 deliveries a second. Benchmark scripts and methodology are in the repository.
Protocol
Simple by design
No handshake, no auth negotiation, no subscription dance. Connect, receive your ID, start sending. Four frame types cover everything.
On connect, the server immediately sends a welcome frame with the client's assigned UUID. No handshake required — you're in.
// Server → Client (on connect){ "type": "welcome", "id": "a3f1b2c4-5678-..."}Scope
Sharp boundaries, clear purpose
The scope test is simple: a feature belongs in the gateway only if it can be implemented without knowing what the payload means. Everything else belongs in your application.
In the gateway
- Connection management & lifecycle
- Message relay & envelope framing
- Backpressure & queue overflow handling
- Topic / room-based routing (planned)
- Per-connection rate limiting (planned)
- Auth & admission control (planned)
- Delivery semantics & acknowledgements
- Multi-instance backplane (planned)
In your app
- Usernames, profiles, or identity
- Message content interpretation
- Chat history or persistence
- Business logic or domain rules
- Push notifications beyond WebSocket
- REST API endpoints for data
"If it needs to know what the message says, it doesn't belong here."
The Operatives
Four tasks, four faces
Every connection in Akagitsune runs three concurrent tasks — reader, bridge, and writer — plus a lead that ties them together. Meet the cast.
Roadmap
What comes next
Akagitsune is under active development. These are the features on the horizon — all of them pass the scope test.
Topic & Room Routing
NextReplace the single broadcast bus with a topic-based subscription model. Clients subscribe to rooms; messages route only to subscribers — eliminating O(N²) fanout.
Authentication
PlannedToken-based admission control at connection time. The gateway verifies identity without interpreting payload — auth is transport-level, not content-level.
Per-Connection Rate Limiting
PlannedConfigurable ingest rate limits per connection to prevent abuse and smooth traffic spikes. Token bucket or sliding window, decided at the transport layer.
Multi-Instance Backplane
PlannedHorizontal scaling via a shared backplane (Redis, NATS, or a custom protocol) so multiple gateway instances form a single logical relay.
Delivery Acknowledgements
ExploringOptional per-message ack/nack for clients that need delivery guarantees. Still payload-agnostic — the gateway confirms transport, not meaning.