rust
44 lines · 7 steps
Concurrent dashboard aggregation in Axum
An Axum handler fans out four backend calls in parallel and degrades gracefully when the non-critical ones fail.
Explained by
highlit
1use axum::{extract::{Path, State}, http::StatusCode, Json};
2use serde::Serialize;
3use std::sync::Arc;
4
5#[derive(Serialize)]
6pub struct Dashboard {
7 profile: Profile,
8 orders: Vec<Order>,
9 recommendations: Vec<Product>,
10 unread_notifications: u32,
11}
12
13pub async fn get_dashboard(
14 State(state): State<Arc<AppState>>,
15 Path(user_id): Path<i64>,
16) -> Result<Json<Dashboard>, StatusCode> {
17 let (profile, orders, recommendations, notifications) = tokio::join!(
18 state.users.fetch_profile(user_id),
19 state.orders.recent_for_user(user_id, 10),
20 state.catalog.recommend_for(user_id),
21 state.notifications.unread_count(user_id),
22 );
23
24 let profile = profile.map_err(|err| {
25 tracing::error!(%user_id, ?err, "failed to load profile");
26 StatusCode::BAD_GATEWAY
27 })?;
28
29 let orders = orders.unwrap_or_else(|err| {
30 tracing::warn!(%user_id, ?err, "orders unavailable, degrading response");
31 Vec::new()
32 });
33
34 let recommendations = recommendations.unwrap_or_default();
35
36 let unread_notifications = notifications.unwrap_or(0);
37
38 Ok(Json(Dashboard {
39 profile,
40 orders,
41 recommendations,
42 unread_notifications,
43 }))
44}
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1Running independent async calls with join! collapses their latency to the slowest one instead of their sum.
- 2Treat failures by importance: fail the request on critical data, but fall back to empty defaults for optional pieces.
- 3Logging errors before discarding them preserves observability even when you choose to degrade the response.
Related explainers
ruby
class Order class InvalidTransition < StandardError; end TRANSITIONS = {
A state machine for order transitions in Ruby
state-machine
data-driven
error-handling
Intermediate
8 steps
java
public class SlidingLogRateLimiter { private final int maxRequests; private final long windowMillis;
How a sliding-log rate limiter works
rate-limiting
concurrency
sliding-window
Advanced
8 steps
go
package theme import ( "fmt"
Per-tenant HTML templates with Gin's renderer
multi-tenancy
concurrency
html-templates
Advanced
8 steps
rust
use std::cmp::Ordering; pub struct PrefixIndex { entries: Vec<String>,
Prefix search with binary partitioning in Rust
binary-search
sorting
case-insensitive
Intermediate
7 steps
python
import time import threading from enum import Enum from functools import wraps
Building a circuit breaker in Python
circuit-breaker
resilience
decorators
Advanced
7 steps
typescript
import { Injectable } from '@angular/core'; import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent, HttpErrorResponse } from '@angular/common/http'; import { BehaviorSubject, Observable, throwError } from 'rxjs'; import { catchError, filter, take, switchMap } from 'rxjs/operators';
Refreshing auth tokens in an Angular interceptor
http-interceptor
token-refresh
rxjs
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/concurrent-dashboard-aggregation-in-axum-explained-rust-e771/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.