Skip to content

Commit

Permalink
PoC: Integration to tower
Browse files Browse the repository at this point in the history
Signed-off-by: Xuanwo <github@xuanwo.io>
  • Loading branch information
Xuanwo committed Aug 27, 2024
1 parent e731d8b commit 5b36519
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 1 deletion.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[workspace]
members = ["backon"]
members = ["backon", "backon-*"]
resolver = "2"

[workspace.package]
Expand Down
15 changes: 15 additions & 0 deletions backon-tower/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[package]
description = "RetryLayer for Tower based on BackON."
documentation = "https://docs.rs/backon-tower"
name = "backon-tower"
rust-version = "1.70"
version = "0.1.0"

edition.workspace = true
license.workspace = true
repository.workspace = true

[dependencies]
backon = "1"
tower = { git = "https://github.com/tower-rs/tower", rev = "7155101" }
# tower = "0.5"
18 changes: 18 additions & 0 deletions backon-tower/src/layer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
use crate::Retry;
use backon::BackoffBuilder;
use tower::Layer;

pub struct RetryLayer<B: BackoffBuilder + Clone> {
backoff: B,
}

impl<B, S> Layer<S> for RetryLayer<B>
where
B: BackoffBuilder + Clone,
{
type Service = Retry<B, S>;

fn layer(&self, service: S) -> Self::Service {
Retry::new(self.backoff.clone(), service)
}
}
6 changes: 6 additions & 0 deletions backon-tower/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#![feature(impl_trait_in_assoc_type)]

mod layer;
pub use layer::RetryLayer;
mod retry;
pub use self::retry::Retry;
43 changes: 43 additions & 0 deletions backon-tower/src/retry.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
use backon::{BackoffBuilder, Retryable};
use std::future::Future;
use tower::Service;

pub struct Retry<B: BackoffBuilder + Clone, S> {
backoff: B,
service: S,
}

impl<B: BackoffBuilder + Clone, S> Retry<B, S> {
pub fn new(backoff: B, service: S) -> Self {
Retry { backoff, service }
}
}

impl<B, S, Request> Service<Request> for Retry<B, S>
where
Request: Clone,
B: BackoffBuilder + Clone,
S: Service<Request> + Clone,
{
type Response = S::Response;
type Error = S::Error;
type Future = impl Future<Output = Result<S::Response, S::Error>>;

fn poll_ready(
&mut self,
cx: &mut std::task::Context<'_>,
) -> std::task::Poll<Result<(), Self::Error>> {
// NOTE: the Future::poll impl for ResponseFuture assumes that Retry::poll_ready is
// equivalent to Ready.service.poll_ready. If this ever changes, that code must be updated
// as well.
self.service.poll_ready(cx)
}

fn call(&mut self, request: Request) -> Self::Future {
let req = request.clone();
let mut srv = self.service.clone();
let backoff = self.backoff.clone();

(move || srv.call(req.clone())).retry(backoff.clone())
}
}

0 comments on commit 5b36519

Please sign in to comment.