Cancellation token - Request context #3011
Replies: 3 comments 3 replies
-
^ Bump, I've searched all over stack overflow, the web, and discord. This question has come up many times without a meaningful answer or solution. "the server can't really know when the client cancels a request unless it also closes the connection, in which case the actix web server will not poll the handler any more" -Discord Which we know be inherently false given other language authors do just that. It incredibly important to provide mechanisms to propagate client cancellations. These cancellations take many forms e.g. the connection was disconnected, the client set a request level timeout that was exceeded by the server, the client simply closed the connection prematurely. Further examples include N users leaving pages after the page has requested resources from the server. The inability to propagate these cancellations puts the viability of actix_web in production use cases at risk both from a resource perspective but also from a cost perspective. Every cancelled request that is not propagated cost money either represented as computing resources or downstream network I/O. |
Beta Was this translation helpful? Give feedback.
-
@caenguidanos I'm not 100% sure that the hack above works generally speaking. struct RequestContext {
cancellation_token: tokio_util::sync::CancellationToken,
}
impl RequestContext {
fn new() -> Self {
RequestContext {
cancellation_token: CancellationToken::new(),
}
}
}
impl Drop for RequestContext {
fn drop(&mut self) {
// called only after 10 seconds even if the client killed the request
println!("drop for RequestContext called");
self.cancellation_token.cancel();
}
}
#[get("/can_cancel_hack")]
async fn client_can_cancel_drop_hack(req: HttpRequest) -> Result<HttpResponse> {
let ctx = RequestContext::new();
let resp = slow_reply_with_ctx(ctx);
Ok(resp.await?)
}
async fn slow_reply_with_ctx(ctx: RequestContext) -> Result<HttpResponse> {
println!("Going to sleep");
select! {
_ = ctx.cancellation_token.cancelled() => {
println!("cancellation received"); // is never printed if cancelled...
return Ok(HttpResponse::GatewayTimeout().finish());
},
_ = tokio::time::sleep(Duration::from_secs(10)) =>{
// pretend like this made calls to other workers
Ok(HttpResponse::Ok().body("Hey sorry I took so long I was sleeping!"))
},
}
} In the example above, even if the client terminates the requests... e.g. hit the cancel button on postman, the Drop is called only after the end of the |
Beta Was this translation helpful? Give feedback.
-
According to their diagram (also I love the diagrams, all of them!) I don't want to turn this into a language comparison thread. Go is only used as an example because it's very tangible. It seems like what's missing is the propagation of connection errors or disconnects. The LifeCycle is already polling. Languages like Go poll the connections at the contained within the "req: HttpRequest" object is a reference to the Context tied to all those events. This works for HTTP1 and HTTP2. It trivializes determining when a client cancels a request for the engineer implementing any server side APIs or resources. Go does this at the Transport layer. Given how Rust handles memory, it may not be easy to hook into a cancellation reference and bubble it up the same way you might in other languages. Maybe it's possible then to allow N users to optional pass in a handler, a OneShot Channel to listen to, something that is part of the |
Beta Was this translation helpful? Give feedback.
-
Hi!
In some languages like Go and C# we have the concept on
request cancellation
. I expect/try to do the same in Rust ecosystem.For one hand, in Go, we have:
The http library exposes a
RequestContext
that we can pass to the database driver. If the user aborts the request in some way before the query is completed then cancel the query.The same is happening with C#:
I see that
tokio_postgres
has some integration here but i don't find any reference in the actix world.Someone has any idea about how to implement and integrate this is Rust-Actix-TokioPostgres?
Beta Was this translation helpful? Give feedback.
All reactions