A comprehensive demonstration of Apache Iggy message streaming integrated with Axum web framework in Rust.
This project showcases how to build a production-ready message streaming service using:
- Apache Iggy 0.6.0-edge - High-performance message streaming with io_uring shared-nothing architecture
- Iggy SDK 0.8.0-edge.6 - Latest edge SDK for compatibility with edge server features
- Axum 0.8 - Ergonomic and modular Rust web framework
- Tokio - Async runtime for Rust
Apache Iggy is capable of processing millions of messages per second with ultra-low latency, supporting TCP, QUIC, WebSocket, and HTTP transport protocols.
- RESTful API for message publishing and consumption
- True batch message sending (single network call for multiple messages)
- Graceful shutdown with SIGTERM/SIGINT handling
- Input validation and sanitization for resource names
- Comprehensive error handling with
Resulttypes (nounwrap()/expect()in production code) - Zero clippy warnings - strict lints enforced, no
#[allow(...)]in production code - Stream and topic management endpoints
- Health checks and service statistics
- Domain-driven event modeling (User, Order, Generic events)
- Partition-based message routing
- Connection resilience with automatic reconnection and exponential backoff
- Rate limiting with token bucket algorithm (configurable RPS and burst)
- API key authentication with constant-time comparison (timing attack resistant)
- Request ID propagation for distributed tracing
- Configurable CORS with origin whitelist support
- Background stats caching to avoid expensive queries on each request
- Docker Compose setup for local development
- Comprehensive test suite (93 unit tests, 24 integration tests, 20 model tests)
- Integration tests with testcontainers (auto-spins Iggy server)
- Fuzz testing for input validation functions
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Axum HTTP Server β
β (Port 3000) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Middleware Stack β
β Rate Limit β Auth β Request ID β Tracing β CORS β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Handlers β
β βββ health.rs - Health/readiness checks, stats β
β βββ messages.rs - Send/poll messages β
β βββ streams.rs - Stream CRUD operations β
β βββ topics.rs - Topic CRUD operations β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Services β
β βββ producer.rs - Message publishing logic β
β βββ consumer.rs - Message consumption logic β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β IggyClientWrapper (with auto-reconnection) β
β High-level wrapper around Iggy SDK β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Apache Iggy Server β
β TCP (8090) / QUIC (8080) / HTTP (3000) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
- Rust 1.90+ (edition 2024, MSRV: 1.90.0)
- Docker & Docker Compose
- curl or httpie (for testing)
cd iggy_sample
cp .env.example .envdocker-compose up -d iggycargo runThe server will start on http://localhost:3000 (or the port specified in .env).
curl http://localhost:3000/healthExpected response:
{
"status": "healthy",
"iggy_connected": true,
"version": "0.1.0",
"timestamp": "2024-01-15T10:30:00Z"
}| Endpoint | Method | Description |
|---|---|---|
/health |
GET | Health check with Iggy connection status |
/ready |
GET | Kubernetes readiness probe (200 if ready) |
/stats |
GET | Service statistics (streams, messages, uptime) |
| Endpoint | Method | Description |
|---|---|---|
/messages |
POST | Send a single message |
/messages |
GET | Poll messages |
/messages/batch |
POST | Send multiple messages |
| Endpoint | Method | Description |
|---|---|---|
/streams/{stream}/topics/{topic}/messages |
POST | Send to specific topic |
/streams/{stream}/topics/{topic}/messages |
GET | Poll from specific topic |
| Endpoint | Method | Description |
|---|---|---|
/streams |
GET | List all streams |
/streams |
POST | Create a new stream |
/streams/{name} |
GET | Get stream details |
/streams/{name} |
DELETE | Delete a stream |
| Endpoint | Method | Description |
|---|---|---|
/streams/{stream}/topics |
GET | List topics in stream |
/streams/{stream}/topics |
POST | Create a topic |
/streams/{stream}/topics/{topic} |
GET | Get topic details |
/streams/{stream}/topics/{topic} |
DELETE | Delete a topic |
curl -X POST http://localhost:3000/messages \
-H "Content-Type: application/json" \
-d '{
"event": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"event_type": "user.created",
"timestamp": "2024-01-15T10:30:00Z",
"payload": {
"type": "User",
"data": {
"action": "Created",
"user_id": "550e8400-e29b-41d4-a716-446655440001",
"email": "user@example.com",
"name": "John Doe"
}
}
}
}'curl -X POST http://localhost:3000/messages \
-H "Content-Type: application/json" \
-d '{
"event": {
"id": "550e8400-e29b-41d4-a716-446655440002",
"event_type": "order.created",
"timestamp": "2024-01-15T10:31:00Z",
"payload": {
"type": "Order",
"data": {
"action": "Created",
"order_id": "550e8400-e29b-41d4-a716-446655440003",
"user_id": "550e8400-e29b-41d4-a716-446655440001",
"items": [
{
"product_id": "550e8400-e29b-41d4-a716-446655440004",
"quantity": 2,
"unit_price": 29.99
}
],
"total_amount": 59.98
}
}
},
"partition_key": "user-550e8400"
}'curl -X POST http://localhost:3000/messages \
-H "Content-Type: application/json" \
-d '{
"event": {
"id": "550e8400-e29b-41d4-a716-446655440005",
"event_type": "custom.event",
"timestamp": "2024-01-15T10:32:00Z",
"payload": {
"type": "Generic",
"data": {
"custom_field": "any value",
"nested": {"key": "value"}
}
}
}
}'# Poll from partition 1, starting at offset 0
curl "http://localhost:3000/messages?partition_id=1&count=10&offset=0"
# Poll with auto-commit
curl "http://localhost:3000/messages?partition_id=1&count=10&auto_commit=true"curl -X POST http://localhost:3000/messages/batch \
-H "Content-Type: application/json" \
-d '{
"events": [
{
"id": "550e8400-e29b-41d4-a716-446655440006",
"event_type": "batch.event.1",
"timestamp": "2024-01-15T10:33:00Z",
"payload": {"type": "Generic", "data": {"index": 1}}
},
{
"id": "550e8400-e29b-41d4-a716-446655440007",
"event_type": "batch.event.2",
"timestamp": "2024-01-15T10:33:01Z",
"payload": {"type": "Generic", "data": {"index": 2}}
}
]
}'curl -X POST http://localhost:3000/streams \
-H "Content-Type: application/json" \
-d '{"name": "my-stream"}'curl -X POST http://localhost:3000/streams/my-stream/topics \
-H "Content-Type: application/json" \
-d '{"name": "my-topic", "partitions": 3}'curl http://localhost:3000/streamscurl http://localhost:3000/statsConfiguration is loaded from environment variables. See .env.example for all options.
| Variable | Default | Description |
|---|---|---|
HOST |
0.0.0.0 |
Server bind address |
PORT |
3000 |
Server port |
IGGY_CONNECTION_STRING |
iggy://iggy:iggy@localhost:8090 |
Iggy connection string |
IGGY_STREAM |
sample-stream |
Default stream name |
IGGY_TOPIC |
events |
Default topic name |
IGGY_PARTITIONS |
3 |
Partitions for default topic |
RUST_LOG |
info |
Log level (trace, debug, info, warn, error) |
| Variable | Default | Description |
|---|---|---|
MAX_RECONNECT_ATTEMPTS |
0 |
Max reconnect attempts (0 = infinite) |
RECONNECT_BASE_DELAY_MS |
1000 |
Base delay for exponential backoff |
RECONNECT_MAX_DELAY_MS |
30000 |
Max delay between reconnection attempts |
HEALTH_CHECK_INTERVAL_SECS |
30 |
Connection health check interval |
| Variable | Default | Description |
|---|---|---|
RATE_LIMIT_RPS |
100 |
Requests per second (0 = disabled) |
RATE_LIMIT_BURST |
50 |
Burst capacity above RPS limit |
API_KEY |
(none) | API key for authentication (disabled if not set) |
AUTH_BYPASS_PATHS |
/health,/ready |
Comma-separated paths that bypass auth |
CORS_ALLOWED_ORIGINS |
* |
Comma-separated allowed origins |
| Variable | Default | Description |
|---|---|---|
BATCH_MAX_SIZE |
1000 |
Max messages per batch send |
POLL_MAX_COUNT |
100 |
Max messages per poll |
STATS_CACHE_TTL_SECS |
5 |
Stats cache refresh interval |
iggy://username:password@host:port
Example:
iggy://iggy:iggy@localhost:8090
iggy_sample/
βββ .github/
β βββ workflows/
β β βββ ci.yml # Main CI (tests, lint, coverage)
β β βββ pr.yml # PR checks (size, commits, docs)
β β βββ release.yml # Multi-platform release builds
β β βββ extended-tests.yml # Weekly stress/benchmark tests
β βββ dependabot.yml # Automated dependency updates
β βββ pull_request_template.md
βββ Cargo.toml # Dependencies and metadata
βββ Dockerfile # Multi-stage build for production
βββ docker-compose.yaml # Local development setup
βββ deny.toml # License/security policy (cargo-deny)
βββ .env.example # Environment variable template
βββ CLAUDE.md # Project documentation for AI assistants
βββ README.md # This file
βββ src/
β βββ main.rs # Application entry point
β βββ lib.rs # Library exports
β βββ config.rs # Configuration from environment
β βββ error.rs # Error types with HTTP status codes
β βββ state.rs # Shared application state
β βββ routes.rs # Route definitions
β βββ iggy_client.rs # Iggy SDK wrapper
β βββ validation.rs # Input validation utilities
β βββ middleware/
β β βββ mod.rs # Middleware exports
β β βββ rate_limit.rs # Token bucket rate limiting
β β βββ auth.rs # API key authentication
β β βββ request_id.rs # Request ID propagation
β βββ models/
β β βββ mod.rs # Model exports
β β βββ event.rs # Domain events (uses rust_decimal)
β β βββ api.rs # API request/response types
β βββ services/
β β βββ mod.rs # Service exports
β β βββ producer.rs # Message producer service
β β βββ consumer.rs # Message consumer service
β βββ handlers/
β βββ mod.rs # Handler exports
β βββ health.rs # Health endpoints
β βββ messages.rs # Message endpoints
β βββ streams.rs # Stream management
β βββ topics.rs # Topic management
βββ tests/
β βββ integration_tests.rs # End-to-end API tests
β βββ model_tests.rs # Unit tests for models
βββ fuzz/
βββ Cargo.toml # Fuzz testing configuration
βββ fuzz_targets/
βββ fuzz_validation.rs # Validation function fuzz tests
cargo testIntegration tests require a running server:
# Terminal 1: Start services
docker-compose up -d iggy
cargo run &
# Terminal 2: Run integration tests
cargo test --test integration_tests -- --ignoredcargo install cargo-tarpaulin
cargo tarpaulin --out Html# Start everything (Iggy + App)
docker-compose up -d
# View logs
docker-compose logs -f app
# Stop
docker-compose downdocker build -t iggy-sample .
docker run -p 8000:8000 -e IGGY_CONNECTION_STRING=iggy://iggy:iggy@host.docker.internal:8090 iggy-sampleEvents follow a structured format with type-safe payloads:
{
"id": "uuid",
"event_type": "domain.action",
"timestamp": "ISO8601",
"payload": {
"type": "User|Order|Generic",
"data": { ... }
},
"correlation_id": "optional-uuid",
"source": "optional-service-name"
}Created- New user registrationUpdated- User profile updateDeleted- User account deletionLoggedIn- User authentication
Created- New order placedUpdated- Order status changeCancelled- Order cancellationShipped- Order shipment
- Any JSON payload for flexible use cases
All errors return structured JSON responses:
{
"error": "error_type",
"message": "Human-readable message",
"details": "Optional additional context"
}| Error Type | HTTP Status | Description |
|---|---|---|
connection_failed |
503 | Iggy server unavailable |
stream_error |
500 | Stream operation failed |
topic_error |
500 | Topic operation failed |
send_error |
500 | Message send failed |
poll_error |
500 | Message poll failed |
not_found |
404 | Resource not found |
bad_request |
400 | Invalid request data |
This application implements multiple security layers suitable for production deployment.
| Feature | Location | Description |
|---|---|---|
| CORS | src/routes.rs |
Configurable origin whitelist via CORS_ALLOWED_ORIGINS using tower-http |
| API Key Authentication | src/middleware/auth.rs |
Constant-time comparison to prevent timing attacks |
| Rate Limiting | src/middleware/rate_limit.rs |
Token bucket algorithm via Governor, configurable RPS and burst |
| Brute Force Protection | src/middleware/auth.rs |
Per-IP tracking of failed authentication attempts |
| Input Validation | src/validation.rs |
Sanitization of stream names, topic names, and event types |
| Trusted Proxy Support | src/middleware/ip.rs |
X-Forwarded-For validation against configurable CIDR ranges |
| Request ID Propagation | src/middleware/request_id.rs |
UUIDv4 generation for distributed tracing |
| Security Audit | .github/workflows/ci.yml |
Automated cargo-audit vulnerability scanning in CI |
| Vulnerability Reporting | SECURITY.md |
Responsible disclosure policy |
| Feature | Reason |
|---|---|
| JWT | API keys are appropriate for service-to-service auth; JWT adds complexity without benefit for this use case |
| RBAC/ABAC | Single-purpose demonstration application, not a multi-tenant system |
| Encrypted cache | Stats cache is internal, read-only, and contains no sensitive data |
For deployment guidelines (reverse proxy configuration, trusted proxies), see CLAUDE.md.
- Batch Operations: Use
/messages/batchfor high-throughput scenarios - Partitioning: Configure appropriate partition count for parallelism
- Partition Keys: Use consistent keys for ordered processing within a partition
- Auto-Commit: Enable for at-least-once delivery semantics
- Connection Pooling: The client maintains persistent connections
Key dependencies (see Cargo.toml for full list):
| Crate | Version | Purpose |
|---|---|---|
iggy |
0.8.0-edge.6 | Iggy Rust SDK (edge) |
axum |
0.8 | Web framework |
tokio |
1.48 | Async runtime |
serde |
1.0 | Serialization |
tracing |
0.1 | Structured logging |
thiserror |
2.0 | Error handling |
governor |
0.8 | Rate limiting (token bucket) |
subtle |
2.6 | Constant-time comparison |
tower-http |
0.6 | HTTP middleware (CORS, tracing) |
rust_decimal |
1.37 | Exact decimal arithmetic for money |
uuid |
1.18 | UUID generation |
chrono |
0.4 | Date/time handling |
testcontainers |
0.24 | Integration testing |
This project uses GitHub Actions for continuous integration and deployment:
| Workflow | Trigger | Description |
|---|---|---|
ci.yml |
Push, PR | Tests, linting, coverage, security audit |
pr.yml |
PR | Size checks, conventional commits, semver |
release.yml |
Tag v* |
Multi-platform builds, GitHub release |
extended-tests.yml |
Weekly | Benchmarks, stress tests, memory checks |
- Formatting:
cargo fmt --check - Linting:
cargo clippy -- -D warnings - Tests: Matrix across 3 OSes Γ 3 Rust versions
- Coverage: Uploaded to Codecov
- Security:
cargo-auditvulnerability scanning - Licenses:
cargo-denycompliance checking
Automatically creates PRs for:
- Cargo dependency updates (weekly)
- GitHub Actions updates (weekly)
- architecture.md - Detailed architecture documentation
- CLAUDE.md - Project documentation for AI assistants
This project is licensed under the MIT License - see the LICENSE file for details.
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'feat: add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request