rust
48 lines · 8 steps
Streaming live price ticks with SSE in Axum
An Axum handler turns a broadcast channel into a Server-Sent Events stream that pushes JSON price updates to every connected client.
Explained by
highlit
1use axum::{
2 response::sse::{Event, KeepAlive, Sse},
3 routing::get,
4 Router,
5};
6use futures::stream::Stream;
7use serde::Serialize;
8use std::{convert::Infallible, sync::Arc, time::Duration};
9use tokio::sync::broadcast;
10use tokio_stream::{wrappers::BroadcastStream, StreamExt};
11
12#[derive(Clone, Serialize)]
13struct PriceTick {
14 symbol: String,
15 price: f64,
16 change: f64,
17}
18
19#[derive(Clone)]
20struct AppState {
21 ticks: broadcast::Sender<PriceTick>,
22}
23
24pub fn routes(ticks: broadcast::Sender<PriceTick>) -> Router {
25 Router::new()
26 .route("/prices/stream", get(stream_prices))
27 .with_state(Arc::new(AppState { ticks }))
28}
29
30async fn stream_prices(
31 axum::extract::State(state): axum::extract::State<Arc<AppState>>,
32) -> Sse<impl Stream<Item = Result<Event, Infallible>>> {
33 let stream = BroadcastStream::new(state.ticks.subscribe()).filter_map(|tick| {
34 let tick = tick.ok()?;
35 let event = Event::default()
36 .event("tick")
37 .id(tick.symbol.clone())
38 .json_data(&tick)
39 .ok()?;
40 Some(Ok(event))
41 });
42
43 Sse::new(stream).keep_alive(
44 KeepAlive::new()
45 .interval(Duration::from_secs(15))
46 .text("keep-alive"),
47 )
48}
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1A broadcast channel fans one producer out to many subscribers, making it a natural backbone for live SSE feeds.
- 2Mapping a stream into Result<Event, _> lets Axum handle the SSE wire format while you focus on payload shape.
- 3Keep-alive comments prevent idle connections and proxies from dropping a long-lived event stream.
Related explainers
rust
use std::collections::HashMap; use std::sync::{Arc, Mutex}; use std::thread;
Aggregating metrics across threads in Rust
concurrency
shared-state
mutex
Intermediate
7 steps
rust
use std::sync::{mpsc, Arc, Mutex}; use std::thread; use std::time::Duration;
Building a thread pool in Rust
concurrency
channels
thread-pool
Advanced
9 steps
python
import csv import io from datetime import datetime
Streaming a CSV export in Flask
streaming
generators
csv
Intermediate
9 steps
rust
use std::time::Instant; use tracing::info; pub struct Timer {
A scope-guard timer with Drop in Rust
raii
drop-guard
timing
Intermediate
7 steps
rust
use std::collections::HashMap; pub struct Memoizer<K, V, F> { cache: HashMap<K, V>,
A generic memoizer in Rust
memoization
generics
caching
Intermediate
6 steps
python
import csv import io from datetime import date
Streaming a CSV export in FastAPI
streaming
async-generators
csv
Advanced
8 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/streaming-live-price-ticks-with-sse-in-axum-explained-rust-b682/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.