rust 50 lines · 7 steps

A maintenance-mode gate in Axum

An Axum middleware that flips the whole API into a 503 response while a shared flag is switched on.

Explained by highlit
1use std::sync::Arc;
2use std::sync::atomic::{AtomicBool, Ordering};
3 
4use axum::body::Body;
5use axum::extract::State;
6use axum::http::{header, Request, StatusCode};
7use axum::middleware::Next;
8use axum::response::{IntoResponse, Json, Response};
9use serde_json::json;
10 
11#[derive(Clone)]
12pub struct MaintenanceState {
13 enabled: Arc<AtomicBool>,
14 retry_after_secs: u64,
15}
16 
17impl MaintenanceState {
18 pub fn new(retry_after_secs: u64) -> Self {
19 Self {
20 enabled: Arc::new(AtomicBool::new(false)),
21 retry_after_secs,
22 }
23 }
24 
25 pub fn set(&self, on: bool) {
26 self.enabled.store(on, Ordering::Relaxed);
27 }
28}
29 
30pub async fn maintenance_guard(
31 State(state): State<MaintenanceState>,
32 request: Request<Body>,
33 next: Next,
34) -> Response {
35 if state.enabled.load(Ordering::Relaxed) {
36 let body = Json(json!({
37 "error": "service_unavailable",
38 "message": "The service is temporarily down for maintenance.",
39 }));
40 
41 return (
42 StatusCode::SERVICE_UNAVAILABLE,
43 [(header::RETRY_AFTER, state.retry_after_secs.to_string())],
44 body,
45 )
46 .into_response();
47 }
48 
49 next.run(request).await
50}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1An Arc<AtomicBool> lets many request handlers read a toggle concurrently while an admin path flips it, with no locks.
  2. 2Axum middleware can short-circuit the request by returning a Response instead of calling next.run.
  3. 3Pairing a 503 with a Retry-After header tells clients to back off politely instead of hammering the server.

Related explainers

Share this explainer

Here's the card — post it anywhere.

A maintenance-mode gate in Axum — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code