3 个不稳定版本
0.2.0 | 2023 年 11 月 20 日 |
---|---|
0.1.1 | 2023 年 7 月 18 日 |
0.1.0 | 2023 年 7 月 17 日 |
1724 在 网络编程
每月 38 次下载
在 tower-async-http 中使用
185KB
2.5K SLoC
Tower Async
Tower Async 是一个模块化和可重用的组件库,用于构建健壮的网络客户端和服务器。
分叉
Tower Async 是从 https://github.com/tower-rs/tower 分叉出来的,并利用 async traits
来简化事物,并使将异步函数集成到中间件变得更加容易。
如果您想看到一个使用
tower_async
相比tower
更简单的示例,您可以看到这里的一个示例使用
tower
的延迟服务: https://github.com/plabayo/tower-async/blob/4ae0c4747fac6cc69b27c87a7ea5cacdd8bab3fb/tower-async-bridge/src/into_async/async_layer.rs#L91-L169。同样的服务可以用
tower_async
按如下方式编写#[derive(Debug)] struct DelayService<S> { inner: S, delay: std::time::Duration, } impl<S> DelayService<S> { fn new(inner: S, delay: std::time::Duration) -> Self { Self { inner, delay } } } impl<S, Request> tower_async_service::Service<Request> for DelayService<S> where S: tower_async_service::Service<Request>, { type Response = S::Response; type Error = S::Error; async fn call(&self, request: Request) -> Result<Self::Response, Self::Error> { tokio::time::sleep(self.delay).await; self.inner.call(request) } }
如果您将此与链接的
tower
版本进行比较,您可能同意,如果您不需要自己编写 future 状态机,那么事情将会简单得多,这正是我们最初引入async
语法的原因。当然,我确实承认,如果您利用了如 https://docs.rs/futures-util-preview/latest/futures-util/future/index.html 这样的 crate 提供的惊人的实用工具,您可以在不自己编写 future 的情况下编写几乎相同的代码。
然而,这并不总是可能的,这也意味着你需要(1)了解这一点,并且(2)将其作为一个依赖项拉取,以及它带来的所有内容。而在现实中,你真的只想能够以
async
方式编写你的中间件。我们充分认识到
tower
不得不采用其使用的方法,因为在许多年里,这简单是唯一合理的做法,除非你想强迫你的用户使用 https://docs.rs/async-trait/latest/async_trait/,这不是每个人都愿意做出的选择,有时他们甚至可能没有这样的奢侈去做。
欢迎加入我们的 Discord,在 Discord 的 #tower-async
公共频道,或者直接在 Tokio 的 Tower Discord 中@@glendc
。
在适当的情况下,我们将(手动)与 Tower 保持同步,如果有机会,我们也会“向上游”做出贡献。然而,鉴于我们的多样性很大,我们不确定这有多可能。
这组库最适合在自己的生态系统中使用,也就是说,只使用 tower-async
库及其依赖项。至少,我们希望 tower-async
成为需要时使用 tower
(经典)(中间件)层的木偶。
如果你想了解如何在 tower-async
环境中纯操作,可以探索 Rama 代码库,这是一个代理框架,完全使用 tower-async
思维方式编写的,也是启动此分叉的主要动机。
然而,你也可以以其他方式将 tower
和 tower-async
连接起来。请参阅“连接到 Tokio 的官方 Tower 生态系统”章节以获取更多关于如何做到这一点的信息。
概述
Tower Async 旨在尽可能简单易用地构建健壮的网络客户端和服务器。它是协议无关的,但设计在请求/响应模式周围。如果你的协议完全是流式的,那么 Tower 可能不适合。
Tower Async 提供了一个简单的核心抽象,即 Service
特性,它表示一个异步函数,接受一个请求并返回响应或错误。这个抽象可以用来模拟客户端和服务器。
像超时这样的通用组件可以建模为包装某些内部服务的 Service
,并在调用内部服务之前或之后应用额外的行为。这允许以协议无关和可组合的方式实现这些组件。通常,这些服务被称为 中间件。
增加了一种抽象,即Layer
trait,用于将中间件与Service
组合。如果将Service
视为从请求类型到响应类型的异步函数,则Layer
是一个函数,它接受一个类型的Service
并返回一个不同类型的Service
。使用ServiceBuilder
类型,可以通过组合多个Layer
来向服务添加中间件。
与Tokio官方Tower生态系统有何不同?
- 使用
Async Traits
(RFC-3185: Static async fn in traits)而不是要求用户手动实现Futures;- 这实际上迫使用户将依赖于不可命名的Futures的服务装箱,例如,用户可能需要使用来自更广泛的Tokio生态系统中的常用实用函数时遇到的由
async functions
返回的服务;
- 这实际上迫使用户将依赖于不可命名的Futures的服务装箱,例如,用户可能需要使用来自更广泛的Tokio生态系统中的常用实用函数时遇到的由
- 放弃
poll_ready
的概念(参见常见问题解答)。 - 使用
&self
代替&mut self
来调用Service::call
,以简化其使用;- 这使其更易于使用;
- 明确指出用户负责适当的资源共享;
- 使其更符合生态系统(例如,
hyper
(v1)也通过&self
获取服务);
连接到Tokio的官方Tower生态系统
您可以使用此存储库中位于./tower-async-bridge目录的tower-async-bridge
crate,并在crates.io上以相同名称发布。
从高层次来看,它允许您
- 将一个
tower::Service
转换为tower_async::Service
(需要into_async
功能); - 将一个
tower_async::Service
转换为tower::Service
; - 在
tower
环境中使用一个tower_async::Layer
(例如,tower::ServiceBuilder
); - 在
tower::Layer
(请访问tower_async
环境(例如tower_async::ServiceBuilder
(需要into_async
功能)中使用;
请检查该软件包的单元测试和示例,以了解如何具体使用该软件包来实现此目的。
此外,我们敦促您仅将此类方法用作过渡目的,而不是作为永久的生活方式。我们认为最好的方法是使用一个或另一个,而不是将两者结合。但如果您绝对必须结合使用一个与其他,tower-async-bridge
应该允许您做到这一点。
塔异步生态系统
塔异步由以下软件包组成
tower-async
(此软件包)tower-async-bridge
tower-async-service
tower-async-layer
tower-async-test
tower-async-http
由于Service
和Layer
特质对于所有使用塔的库都是重要的集成点,因此它们尽可能保持稳定,并且很少进行破坏性更改。因此,它们定义在单独的软件包中,tower-async-service
和tower-async-layer
。此软件包包含这些核心特质的重新导出,常用中间件的实现,以及与Service
和Layer
一起工作的实用工具。
tower-async-bridge
用于将Tokio的官方塔生态系统与这个(异步特质)版本(分支)连接起来。
使用tower-async-test
可以非常容易地进行Layer
的单元测试。
最后,如果您使用tower-async
进行HTTP目的(例如HTTP Web服务器),那么您可能会发现同时使用tower-async-http
很有用,因为它提供了专门针对HTTP目的的构建器扩展和中间件。
用法
塔(异步)提供了一层抽象,以及各种中间件的泛型实现。这意味着仅靠tower-async
软件包本身不提供网络客户端或服务器的有效实现。相反,塔的Service
特质提供应用程序代码、提供中间件实现的库以及实现各种网络协议服务器和/或客户端的库之间的集成点。
根据您的特定用例,您可能以多种方式使用塔
-
实现网络程序的应用逻辑。您可以使用
Service
特质来模拟应用程序的行为,并使用此软件包和由其他库提供的中间件来添加由一个或多个协议实现提供的客户端和服务器功能。 -
实现中间件 以可重用方式添加自定义行为到网络客户端和服务器。这可能是一般用途中间件(如果是,请考虑将您的中间件作为库发布给其他Tower用户!)或需要在多个客户端或服务器之间共享的应用特定行为。
-
实现网络协议。实现网络协议(如HTTP)的库可以依赖
tower-async-service
来使用Service
特性作为协议和用户代码之间的集成点。例如,某些协议的客户端可能实现Service
,使用户可以向这些客户端添加任意Tower中间件。同样,服务器可能是由用户提供的Service
创建的。此外,当网络协议需要由现有Tower中间件提供的功能时,协议实现可能使用Tower中间件作为内部集成点。
库支持
以下是一些使用Tower Async(而不是Tower)和 Service
特性的库
rama
:一个匿名化您的网络流量的代理框架。
如果您是支持Tower Async的crate的维护者,我们很乐意将您的crate添加到此列表!请 提交一个PR,添加对您库的简要描述!
入门指南
此crate提供的各种中间件实现都带有功能标志,以便用户只能编译他们需要的Tower部分。默认情况下,所有可选中间件都被禁用。
要开始使用Tower的所有可选中间件,请将以下内容添加到您的 Cargo.toml
tower-async = { version = "0.2", features = ["full"] }
或者,您可以选择只启用某些功能。例如,要仅启用 timeout
中间件,请编写
tower-async = { version = "0.2", features = ["timeout"] }
有关Tower提供的中介件的完整列表,请参阅 此处。
浏览 tower-async-http/examples
中的示例,了解如何使用 tower-async
和其相关crate的一些示例。虽然这些示例主要集中在http上,但请注意
tower-async
可用于任何请求-响应流程(类似于tower
);- 您还可以使用
tower-async
与http web服务一起使用,而无需使用tower-async-http
crate,它只是为了提供针对http特定目的的额外中间件,但这完全是可选的。
文档还包含一些更小的示例,当然,您也可以阅读代码库及其单元测试。
支持的Rust版本
目前Tower Async需要nightly Rust,并且目前没有向后兼容性的承诺。
一旦 async traits
稳定,我们将再次开始支持稳定Rust,并开始努力实现向后兼容性。
有关Rust语言核心团队此路线图的信息,请参阅 https://blog.rust-lang.net.cn/inside-rust/2023/05/03/stabilizing-async-fn-in-trait.html。
赞助
定期和一次性赞助商 alike 帮助我们支付由所有Plabayo的免费和开源工作产生的开发和运营成本。
我们也是Tokio的月度赞助商,以回报他们所做和持续努力的所有出色工作。
您可以在https://github.com/sponsors/plabayo了解更多关于Plabayo赞助信息。
一次性赞助(即所谓的“买我一杯咖啡”,但通过GitHub Sponsors支付),就像常规赞助一样受欢迎。并不是每个人都具备赞助的财务能力,所以请随意以其他任何您能想到的方式进行贡献。
常见问题解答(FAQ)
Tower的Service中的
poll_ready
方法来自哪里?
为了简化和因为该分支的作者认为这超出了范围的问题,该方法已被移除。
- 大多数Tower服务和层根本不需要
poll_ready
方法,只是简单地调用内部服务来实现这一点; - 出于某些背压目的,您确实想了解请求以便知道如何处理它,所以
poll_ready
不适用于这些情况;
poll_ready
也被用于负载均衡服务,但这被认为超出了范围。
- 在我们的观点中,负载均衡传入的网络流更适合由您服务的周边网络基础设施(使用一个...负载均衡器)来处理;
- 再次……如果您确实想在服务内部进行负载均衡,那可能是因为您实际上需要请求的上下文来知道该做什么,在这种情况下,
poll_ready
对您来说不起作用;
如果您在Tower(异步)服务内部仍想应用某种速率限制、背压或负载均衡,您应该在call
函数内部进行。
然而,这个分支仍处于早期阶段,所以如果您对这个话题有不同的看法,请随意开始讨论。这个库的作者始终欢迎反馈,但保留拒绝任何他们希望拒绝的请求的权利。
我的最喜欢的Tower实用工具在哪里?
由于所有tower代码都必须手动移植,可能缺少一些功能。tower生态系统也继续繁荣发展,因此那里可能还会添加新的功能。如果您希望添加/移植此类功能,请随时与我们交谈或在GitHub上提交问题。
请注意,某些功能是故意不支持
- 所有与“ready”相关的功能都有意移除,因为我们认为这超出了范围。
- 因此,也不支持依赖于此或在此基础上构建的所有实用工具。
请参阅前面的FAQ,以了解我们关于负载均衡等问题的观点。
许可证
该项目根据MIT许可证授权。
向原始Tower作者表示衷心的感谢和致意,他们的代码也以相同的许可证类型授权。
贡献
除非您明确说明,否则您有意提交以供Tower Async包含的任何贡献,均应按照MIT许可证授权,不附加任何其他条款或条件。
依赖项
~0–1.4MB
~25K SLoC