2 releases
| 0.1.1 | Dec 1, 2025 |
|---|---|
| 0.1.0 | Nov 30, 2025 |
#1840 in Encoding
Used in 3 crates
21KB
431 lines
Pulse
The world's fastest realtime communication engine for web and edge applications.
Pulse is a high-performance, transport-agnostic pub/sub messaging system built in Rust. It's designed for applications that need sub-millisecond latency and massive scale.
Features
- Blazing Fast: Lock-free data structures, zero-copy message passing
- Transport Agnostic: WebSocket today, WebTransport tomorrow
- Protocol Efficient: Binary MessagePack encoding
- Developer Friendly: Simple pub/sub API
- Observable: Built-in Prometheus metrics
- Production Ready: Comprehensive error handling and logging
Quick Start
Installation
# From crates.io
cargo install tenvis-pulse-server
# From source
git clone https://github.com/tenvisio/pulse
cd pulse
cargo build --release
Run the Server
# With defaults (localhost:8080)
pulse
# With custom port
PULSE_PORT=9000 pulse
# With config file
pulse --config pulse.toml
Connect a Client
Messages use MessagePack encoding with a 4-byte length prefix. Here's the message structure:
// Subscribe to a channel
{ type: 'subscribe', id: 1, channel: 'chat:lobby' }
// Publish a message
{ type: 'publish', channel: 'chat:lobby', payload: /* msgpack bytes */ }
// Unsubscribe
{ type: 'unsubscribe', id: 2, channel: 'chat:lobby' }
Note: The wire format requires a 4-byte big-endian length prefix before each MessagePack frame. See
examples/web-client/for a complete working browser implementation, or wait for the upcoming TypeScript SDK.
Architecture
┌────────────────────────────────────────────────────────────┐
│ pulse-server │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
│ │ Config │ │ Metrics │ │ Handlers │ │
│ └─────────────┘ └─────────────┘ └─────────────────────┘ │
└────────────────────────────────────────────────────────────┘
│
▼
┌────────────────────────────────────────────────────────────┐
│ pulse-core │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
│ │ Router │ │ Channel │ │ Presence │ │
│ └─────────────┘ └─────────────┘ └─────────────────────┘ │
└────────────────────────────────────────────────────────────┘
│
▼
┌────────────────────────────────────────────────────────────┐
│ pulse-transport │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
│ │ WebSocket │ │ WebTransport│ │ Fallback │ │
│ └─────────────┘ └─────────────┘ └─────────────────────┘ │
└────────────────────────────────────────────────────────────┘
│
▼
┌────────────────────────────────────────────────────────────┐
│ pulse-protocol │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
│ │ Frames │ │ Codec │ │ Version │ │
│ └─────────────┘ └─────────────┘ └─────────────────────┘ │
└────────────────────────────────────────────────────────────┘
Crates
| Crate | Description |
|---|---|
pulse-protocol |
Wire protocol definitions and codec |
tenvis-pulse-core |
Router, channels, and presence |
tenvis-pulse-transport |
Transport abstractions (WebSocket, WebTransport) |
tenvis-pulse-server |
The server binary |
tenvis-pulse-bench |
Performance benchmarks |
Configuration
Create a pulse.toml file:
[server]
host = "0.0.0.0"
port = 8080
[transport]
websocket = true
webtransport = false # Experimental
[limits]
max_connections = 100000
max_channels = 10000
max_subscriptions_per_connection = 100
max_message_size = 65536 # 64 KB
[heartbeat]
interval_ms = 30000
timeout_ms = 60000
[metrics]
enabled = true
port = 9090
Or use environment variables:
export PULSE_HOST=0.0.0.0
export PULSE_PORT=8080
export PULSE_LIMITS_MAX_CONNECTIONS=100000
Protocol
Pulse uses a binary protocol based on MessagePack. See the full Protocol Specification.
Frame Types
| Type | Direction | Description |
|---|---|---|
| Subscribe | Client → Server | Subscribe to a channel |
| Unsubscribe | Client → Server | Unsubscribe from a channel |
| Publish | Bidirectional | Send message to channel |
| Presence | Bidirectional | Presence updates |
| Ack | Server → Client | Acknowledgment |
| Error | Server → Client | Error response |
| Ping/Pong | Bidirectional | Keepalive |
Benchmarks
Run benchmarks:
# Run micro-benchmarks (Criterion)
cargo bench -p tenvis-pulse-bench
# Run specific benchmark file
cargo bench -p tenvis-pulse-bench --bench throughput
cargo bench -p tenvis-pulse-bench --bench latency
# Run end-to-end throughput test (requires server running)
# Terminal 1: Start the server
cargo run --release -p tenvis-pulse-server
# Terminal 2: Run e2e benchmark with 16 clients (default)
cargo run --release -p tenvis-pulse-bench --bin e2e_throughput
# Or with custom client count
cargo run --release -p tenvis-pulse-bench --bin e2e_throughput -- 64
Results
| Metric | Time | Throughput |
|---|---|---|
| Encode 64B message | 217ns | 280 MiB/s |
| Encode 1KB message | 241ns | 3.9 GiB/s |
| Encode 64KB message | 4.9µs | 12.3 GiB/s |
| Decode 64B message | 150ns | 719 MiB/s |
| Decode 1KB message | 178ns | 5.6 GiB/s |
| Decode 64KB message | 1.7µs | 35.1 GiB/s |
| Publish (any subscriber count) | 87ns | — |
| Subscribe operation | 163ns | — |
| Pub/sub roundtrip | 170ns | — |
Fanout Performance
| Subscribers | Time | Throughput |
|---|---|---|
| 10 | 88ns | 112M elem/s |
| 100 | 88ns | 1.1B elem/s |
| 1,000 | 88ns | 11.4B elem/s |
| 10,000 | 88ns | 113B elem/s |
Note: Publish time is constant regardless of subscriber count thanks to efficient broadcast channels.
Benchmarks run on Apple M2 MacBook Air, results will vary.
Comparison
| Feature | Pulse | Socket.io | Phoenix Channels |
|---|---|---|---|
| Language | Rust | Node.js | Elixir |
| Protocol | Binary (MessagePack) | JSON | JSON/Binary |
| Transport | WS, WebTransport | WS, Polling | WS |
| Latency | Sub-ms | ~10-50ms | ~1-5ms |
| Memory per connection | ~1KB | ~10KB | ~5KB |
Roadmap
- Core pub/sub router
- WebSocket transport
- Presence tracking
- Prometheus metrics
- Docker images
- WebTransport support
- Redis adapter for clustering
- Message persistence/replay
- TypeScript client SDK
- Authentication hooks
- Rate limiting
Contributing
We welcome contributions! Please see our Contributing Guide.
# Setup
git clone https://github.com/tenvisio/pulse
cd pulse
cargo build
# Run tests
cargo test
# Run clippy
cargo clippy -- -D warnings
# Format code
cargo fmt
License
Pulse is dual-licensed under the MIT License and Apache License 2.0.
Acknowledgments
Built with:
- Tokio - Async runtime
- Axum - Web framework
- DashMap - Concurrent hashmap
- MessagePack - Efficient serialization
Built by tenvisio
lib.rs:
pulse-protocol
Wire protocol definitions for the Pulse realtime communication engine.
This crate defines the binary protocol used for communication between Pulse clients and servers, including frame types, codecs, and versioning.
Frame Types
Subscribe/Unsubscribe- Channel membershipPublish- Send messages to channelsPresence- Track online usersAck/Error- Acknowledgments and errors
Example
use pulse_protocol::{Frame, codec};
// Create a publish frame using the helper method
let frame = Frame::publish("chat:lobby", b"Hello, world!".to_vec());
// Encode and decode
let encoded = codec::encode(&frame).unwrap();
let decoded = codec::decode(&encoded).unwrap();
Dependencies
~0.9–1.9MB
~38K SLoC