A short addendum to the async rewrite I wrote up earlier, because one thing deserves its own note: cancellation, and specifically tokio::select!. It's the feature I reached for most often and also the one that caught me out, so here's the warning I wish I'd had.
select! runs several futures concurrently and returns as soon as the first one completes. The trap is the word "first". When one branch completes, the others are dropped. Not paused, not finished, dropped, right where they were, mid-await. If one of those branches was halfway through writing to a socket, or had taken a lock, or was midway through a database transaction, that work is now abandoned at exactly the point it had reached.
tokio::select! {
_ = process_batch(&mut conn) => { /* done */ }
_ = shutdown.recv() => {
// process_batch is dropped here, possibly mid-write
}
}
I had a loop that selected on "do the next unit of work" against "shutdown signal", and on shutdown it would occasionally leave a half-written record because the work future was cancelled partway through its write. No error. The future just stopped existing at its current .await point, and any I/O it hadn't flushed never happened.
The fix is to know which of your operations are safe to cancel and which aren't. Anything that must complete as a unit shouldn't be a select! branch directly. Run it to completion first, or make it cancellation-safe, or guard it so the cancel only takes effect at a boundary where dropping is harmless. The Tokio docs do flag this, the phrase is "cancellation safety", but it didn't land for me until I'd corrupted a few records and gone looking for why.
So: select! is a genuinely good tool, and concurrency that used to take a fiddly hand-rolled state machine is now four lines. Just remember that the losing branches don't lose gracefully. They're dropped where they stand, and if that's mid-write, mid-transaction, or mid-anything-that-matters, you own the consequences. Lead with completion, select for cancellation, and never put something that must finish on the cancellable side of the macro.