Commit 24decf1
committed
Avoid using futures'
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.block_on in the request database guard1 parent 08a7449 commit 24decf1
1 file changed
+8
-4
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
215 | 215 | | |
216 | 216 | | |
217 | 217 | | |
218 | | - | |
| 218 | + | |
219 | 219 | | |
220 | 220 | | |
221 | 221 | | |
| |||
238 | 238 | | |
239 | 239 | | |
240 | 240 | | |
241 | | - | |
| 241 | + | |
242 | 242 | | |
243 | 243 | | |
244 | 244 | | |
245 | | - | |
246 | | - | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
247 | 251 | | |
248 | 252 | | |
249 | 253 | | |
| |||
0 commit comments