You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Avoid using futures' block_on in the request database guard
The request guard works by sending on a channel when it is
dropped. Since we can't do async code in `Drop::drop`, I was using
`futures::executor::block_on` under the (false!) impression that
this *specific* usecase would not be a problem as we are always
pulling from that channel. However, sending on a channel can result in
`Pending` when the Tokio worker's cooperative budget is exhausted,
even if the queue is completely empty!
A simple example:
```rust
// Drain the budget
while task::consume_budget().now_or_never().is_some() {}
// Try to use more budget than we have and block forever
futures::executor::block_on(tx.send(42u8)).unwrap();
```
This `Pending` will never resolve because we are no longer running the
Tokio runtime so it will never see an `.await` and replenish the
budget. With enough bad luck, all the worker threads get stuck like
this and the entire system becomes unavailable.
There are a number of possible workarounds, but the least invasive is
to punt the final logging off to a Tokio task and let it happen
out-of-band. Technically this will make the timing a little bit less
accurate, but I was never worried about exact nanoseconds anyway.
0 commit comments