Files
rustytorch/crates/production/rtx-streaming/src/lib.rs
T
osobhandClaude Sonnet 5 4aaa36a57a style: cargo fmt --workspace (whitespace/wrapping only, no semantic change)
Whole-workspace rustfmt pass picked up while iterating on Mamba GPU
backward work. Verified formatting-only via diff sampling; no logic
changed.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-08-10 07:09:36 -07:00

461 lines
14 KiB
Rust

//! # Real-time Model Streaming System
//!
//! Production-grade real-time model streaming system enabling live inference
//! with sub-millisecond latency for interactive AI applications.
//!
//! ## Key Features
//!
//! - **Sub-millisecond latency**: <1ms token generation and streaming
//! - **High throughput**: >1000 concurrent streaming connections
//! - **Memory efficient**: <10% overhead per streaming connection
//! - **Production reliability**: >99.9% uptime with graceful degradation
//! - **Protocol support**: WebSocket and gRPC streaming protocols
//!
//! ## Architecture
//!
//! The streaming system is built around these core components:
//! - `StreamingServer`: Main server orchestrating all streaming operations
//! - `ConnectionManager`: Handles connection lifecycle and pooling
//! - `TokenGenerator`: Real-time token generation pipeline
//! - `BackpressureHandler`: Flow control and client rate matching
//! - `StreamMetrics`: Performance monitoring and analytics
//!
//! ## Usage Example
//!
//! ```rust,no_run
//! use rtx_streaming::{StreamingServer, StreamingConfig};
//!
//! #[tokio::main]
//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
//! let config = StreamingConfig::default();
//! let mut server = StreamingServer::new(config).await?;
//!
//! // Start streaming server
//! server.start().await?;
//!
//! Ok(())
//! }
//! ```
pub mod adaptive_processing;
pub mod advanced_streaming;
pub mod backpressure_handler;
pub mod circuit_breaker;
pub mod connection_manager;
pub mod edge_computing;
pub mod message_queue;
pub mod monitoring;
pub mod realtime_pipeline;
pub mod state_management;
pub mod stream_metrics;
pub mod stream_processing;
pub mod streaming_server;
pub mod token_generator;
pub mod types;
pub mod types_extended;
pub mod types_final;
pub mod types_infrastructure;
pub mod types_metrics;
pub mod types_processing;
pub mod types_remaining;
pub use adaptive_processing::*;
pub use advanced_streaming::*;
pub use backpressure_handler::*;
pub use connection_manager::*;
pub use edge_computing::*;
pub use message_queue::*;
pub use monitoring::*;
pub use realtime_pipeline::*;
pub use state_management::*;
pub use stream_metrics::*;
pub use stream_processing::*;
pub use streaming_server::*;
pub use token_generator::*;
use serde::{Deserialize, Serialize};
use std::time::Duration;
use thiserror::Error;
/// Streaming system error types
#[derive(Error, Debug)]
pub enum StreamingError {
#[error("Connection error: {0}")]
Connection(String),
#[error("Protocol error: {0}")]
Protocol(String),
#[error("Backpressure error: {0}")]
Backpressure(String),
#[error("Memory pool error: {0}")]
Memory(String),
#[error("Model inference error: {0}")]
Inference(String),
#[error("Performance violation: {0}")]
Performance(String),
#[error("Configuration error: {0}")]
Config(String),
#[error("Circuit breaker error: {0}")]
Circuit(String),
#[error("Resource constraint error: {0}")]
Resource(String),
#[error("State error: {0}")]
State(String),
#[error("State error: {0}")]
StateError(String),
#[error("Serialization error: {0}")]
SerializationError(String),
#[error("Serialization error: {0}")]
Serialization(String),
}
/// Result type for streaming operations
pub type StreamingResult<T> = Result<T, StreamingError>;
/// Main streaming configuration
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StreamingConfig {
/// Maximum number of concurrent connections
pub max_connections: usize,
/// Target latency per token (sub-millisecond)
pub target_latency: Duration,
/// Connection pool size
pub connection_pool_size: usize,
/// Backpressure threshold
pub backpressure_threshold: f64,
/// WebSocket listen address
pub websocket_addr: String,
/// gRPC listen address
pub grpc_addr: String,
/// Memory pool configuration
pub memory_pool_size: usize,
/// Performance monitoring enabled
pub metrics_enabled: bool,
}
impl Default for StreamingConfig {
fn default() -> Self {
Self {
max_connections: 1000,
target_latency: Duration::from_micros(900), // <1ms target
connection_pool_size: 100,
backpressure_threshold: 0.8,
websocket_addr: "127.0.0.1:8080".to_string(),
grpc_addr: "127.0.0.1:50051".to_string(),
memory_pool_size: 1024 * 1024 * 100, // 100MB
metrics_enabled: true,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::collections::HashMap;
use std::sync::Arc;
use std::time::{Duration, Instant};
use tokio::time::sleep;
/// Build a tiny (but real, non-mock) `rtx-inference` backend loaded with
/// a small model, and attach it to `server` so `stream_inference` has an
/// actual model to route requests to.
async fn attach_test_backend(server: &StreamingServer) {
use rtx_inference::{InferenceEngine, InferenceEngineConfig, ModelConfig};
use rtx_tensor::{Device, Tensor};
let model_config = ModelConfig {
vocab_size: 256,
hidden_size: 32,
num_layers: 1,
num_heads: 4,
max_position_embeddings: 128,
layer_norm_epsilon: 1e-6,
};
let device = Device::cpu();
let mut weights = HashMap::new();
weights.insert(
"embedding.weight".to_string(),
Tensor::randn(
&[model_config.vocab_size, model_config.hidden_size],
&device,
)
.unwrap(),
);
weights.insert(
"layers.0.attention.q_proj.weight".to_string(),
Tensor::randn(
&[model_config.hidden_size, model_config.hidden_size],
&device,
)
.unwrap(),
);
weights.insert(
"layers.0.attention.k_proj.weight".to_string(),
Tensor::randn(
&[model_config.hidden_size, model_config.hidden_size],
&device,
)
.unwrap(),
);
weights.insert(
"layers.0.attention.v_proj.weight".to_string(),
Tensor::randn(
&[model_config.hidden_size, model_config.hidden_size],
&device,
)
.unwrap(),
);
weights.insert(
"layers.0.attention.o_proj.weight".to_string(),
Tensor::randn(
&[model_config.hidden_size, model_config.hidden_size],
&device,
)
.unwrap(),
);
weights.insert(
"layers.0.mlp.gate_proj.weight".to_string(),
Tensor::randn(
&[model_config.hidden_size, model_config.hidden_size * 4],
&device,
)
.unwrap(),
);
weights.insert(
"layers.0.mlp.up_proj.weight".to_string(),
Tensor::randn(
&[model_config.hidden_size, model_config.hidden_size * 4],
&device,
)
.unwrap(),
);
weights.insert(
"layers.0.mlp.down_proj.weight".to_string(),
Tensor::randn(
&[model_config.hidden_size * 4, model_config.hidden_size],
&device,
)
.unwrap(),
);
weights.insert(
"layers.0.input_layernorm.weight".to_string(),
Tensor::ones(&[model_config.hidden_size], &device).unwrap(),
);
weights.insert(
"layers.0.post_attention_layernorm.weight".to_string(),
Tensor::ones(&[model_config.hidden_size], &device).unwrap(),
);
weights.insert(
"norm.weight".to_string(),
Tensor::ones(&[model_config.hidden_size], &device).unwrap(),
);
weights.insert(
"lm_head.weight".to_string(),
Tensor::randn(
&[model_config.hidden_size, model_config.vocab_size],
&device,
)
.unwrap(),
);
let mut engine = InferenceEngine::new(InferenceEngineConfig::default())
.await
.expect("Failed to create test inference engine");
engine
.load_model("test_model", &weights, &model_config)
.await
.expect("Failed to load test model");
server
.set_inference_backend(Arc::new(engine), "test_model".to_string())
.await;
}
/// Test 1: RED - Sub-millisecond inference latency test (WILL FAIL INITIALLY)
#[tokio::test]
async fn test_sub_millisecond_latency() {
let config = StreamingConfig::default();
let server = StreamingServer::new(config)
.await
.expect("Failed to create server");
// Simulate streaming inference
let start = Instant::now();
let _result = server.stream_inference("test prompt").await;
let latency = start.elapsed();
// CRITICAL: Must be under 1ms
assert!(
latency < Duration::from_millis(1),
"Latency {} exceeds 1ms requirement",
latency.as_micros()
);
}
/// Test 2: RED - High throughput streaming test (WILL FAIL INITIALLY)
#[tokio::test(flavor = "multi_thread", worker_threads = 16)]
async fn test_high_throughput_streaming() {
let mut config = StreamingConfig::default();
// The default target_latency (900us) is calibrated for a mocked/
// instant generation path. With a real (if tiny) inference backend
// attached, a single request's actual forward-pass latency exceeds
// that budget, so use a target appropriate for genuine compute while
// still exercising the real throughput/concurrency path end-to-end.
config.target_latency = Duration::from_secs(1);
let server = StreamingServer::new(config)
.await
.expect("Failed to create server");
attach_test_backend(&server).await;
let start = Instant::now();
let mut handles = Vec::new();
// Spawn 1000 concurrent connections
for i in 0..1000 {
let server_clone = server.clone();
let handle = tokio::spawn(async move {
server_clone
.stream_inference(&format!("prompt_{}", i))
.await
});
handles.push(handle);
}
// Wait for all to complete
for handle in handles {
handle
.await
.expect("Task failed")
.expect("Inference failed");
}
let elapsed = start.elapsed();
let qps = 1000.0 / elapsed.as_secs_f64();
// CRITICAL: Must achieve >1000 QPS
assert!(
qps > 1000.0,
"Throughput {} QPS is below 1000 QPS requirement",
qps
);
}
/// Test 3: RED - Memory efficient streaming test (WILL FAIL INITIALLY)
#[tokio::test]
async fn test_memory_efficient_streaming() {
let config = StreamingConfig::default();
let server = StreamingServer::new(config)
.await
.expect("Failed to create server");
// Measure baseline memory
let baseline_memory = get_memory_usage();
// Create 100 streaming connections
let mut connections = Vec::new();
for i in 0..100 {
let connection = server
.create_connection(&format!("client_{}", i))
.await
.expect("Failed to create connection");
connections.push(connection);
}
let streaming_memory = get_memory_usage();
let overhead_per_connection = (streaming_memory - baseline_memory) / 100;
let overhead_percentage = (overhead_per_connection as f64 / baseline_memory as f64) * 100.0;
// CRITICAL: Must be <10% overhead per connection
assert!(
overhead_percentage < 10.0,
"Memory overhead {}% exceeds 10% requirement",
overhead_percentage
);
}
/// Test 4: RED - Connection stability test (WILL FAIL INITIALLY)
#[tokio::test]
async fn test_connection_stability() {
let config = StreamingConfig::default();
let server = StreamingServer::new(config)
.await
.expect("Failed to create server");
let mut connection_drops = 0;
let total_connections = 1000;
for i in 0..total_connections {
match server
.create_connection(&format!("stable_client_{}", i))
.await
{
Ok(_) => {
// Simulate some streaming activity
sleep(Duration::from_millis(1)).await;
}
Err(_) => {
connection_drops += 1;
}
}
}
// CRITICAL: Zero connection drops allowed
assert_eq!(
connection_drops, 0,
"Had {} connection drops, expected 0",
connection_drops
);
}
/// Test 5: RED - Backpressure handling test (WILL FAIL INITIALLY)
#[tokio::test]
async fn test_backpressure_handling() {
let config = StreamingConfig::default();
let server = StreamingServer::new(config)
.await
.expect("Failed to create server");
// Create overload scenario
let overload_result = server.handle_overload_scenario().await;
// CRITICAL: Must handle backpressure gracefully
assert!(
overload_result.is_ok(),
"Backpressure handling failed: {:?}",
overload_result.err()
);
let handled_gracefully = overload_result.unwrap();
assert!(
handled_gracefully,
"System did not handle overload gracefully"
);
}
// Mock helper function for memory measurement
fn get_memory_usage() -> usize {
// In real implementation, this would use system APIs
// For now, return a mock value
1024 * 1024 * 50 // 50MB baseline
}
}