Rust 用 tower 中间件栈:用 RetryLayer、TimeoutLayer 与自定义 Layer 收敛横切逻辑

test12026-10-121 次阅读

tower 是 Axum 的底盘

Axum 的 Service 体系来自 tower:每个请求都经过一层层 Layer 包裹的 Service。把超时、重试、日志这些横切逻辑写成 Layer,比在每个 handler 里重复代码干净得多,而且可以组合复用。

用内置 Layer 组合超时与重试

use tower::{ServiceBuilder, timeout::TimeoutLayer, retry::RetryLayer};
use tower::retry::budget::Budget;
use std::time::Duration;

fn build_stack() {
    let budget = Budget::new(Duration::from_secs(10), 0.1, 10);
    let service = ServiceBuilder::new()
        .layer(TimeoutLayer::new(Duration::from_secs(3)))
        .layer(RetryLayer::new(budget))
        .service(my_handler_service);
    // service 现在自带 3s 超时与按预算重试
}

写一个记录耗时的自定义 Layer

实现 Layer 与 Service trait,把计时包在 call 外面。

use std::task::{Context, Poll};
use std::future::Future;
use std::pin::Pin;
use std::time::Instant;
use tower::{Layer, Service};

#[derive(Clone)]
pub struct TraceLayer;

impl<S> Layer<S> for TraceLayer {
    type Service = TraceService<S>;
    fn layer(&self, inner: S) -> Self::Service {
        TraceService { inner }
    }
}

pub struct TraceService<S> { inner: S }

impl<S, Req, Res, F, E> Service<Req> for TraceService<S>
where
    S: Service<Req, Response = Res, Error = E, Future = F> + Send + 'static,
    F: Future<Output = Result<Res, E>> + Send + 'static,
    Req: Send + 'static,
{
    type Response = Res;
    type Error = E;
    type Future = Pin<Box<dyn Future<Output = Result<Res, E>> + Send>>;

    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), E>> {
        self.inner.poll_ready(cx)
    }

    fn call(&mut self, req: Req) -> Self::Future {
        let start = Instant::now();
        let fut = self.inner.call(req);
        Box::pin(async move {
            let res = fut.await;
            println!("elapsed={:?}", start.elapsed());
            res
        })
    }
}

组合顺序的工程经验

  • Layer 包裹顺序从外到内执行:最先 layer 的最外层,最先拿到请求、最后拿到响应。
  • 超时放外层,避免下游重试把整体时间拖长;重试放内层,只针对真正可重试的错误。
  • 自定义 Layer 记得实现 Clone,ServiceBuilder 在构建时会 clone 层,否则编译不过。
T

test1

文章作者

tower 是 Axum 的底盘 Axum 的 Service 体系来自 tower:每个请求都经过一层层 Layer...

分类
技术
发布时间
2026-10-12
字数
约 2013 字
阅读
1 次