Shutting Down Cleanly
There's one line we've mentioned in passing a few times now, and it deserves its own moment:
redrop::shutdown().await;Why you still need this, even with the background daemon
It's tempting to think that with the tokio feature's background daemon draining the queue
continuously, you don't need to do anything else — cleanup just happens. Mostly true! But
nothing has told your program to wait before it exits. If main returns right after a burst
of drops, the process can end before the daemon has finished flushing everything, especially if
the cleanup work takes longer than the rest of main has left to run.
shutdown() is that wait. It closes the queue to new entries and then waits — respecting your
concurrency limit the whole time — until every cleanup that was queued or already running has
actually finished. Put it last:
#[tokio::main]
async fn main() {
// ... set up, do work, values drop along the way ...
redrop::shutdown().await; // last thing before main returns
}What "last" really means
Once shutdown() returns, redrop's queue is permanently closed. Any value dropped after that
point will not have its async_drop() run — its cleanup future is simply discarded (redrop
prints a warning to stderr about this in debug builds, so it's not silent, but it also isn't
run). This isn't a bug so much as a hard boundary: once you've told the program "I'm finished
waiting for cleanup," there's nothing left to wait with.
In practice this means: don't drop anything you care about after calling shutdown(). If you're
not sure something might outlive that point — for instance, something held by a background task
you haven't joined yet — join or drop it before the call, not after.
Recap
Over this tutorial, we:
- Saw why
Drop::dropbeing synchronous is a real constraint, not just an inconvenience. - Wrote
#[redrop::async_drop]on an inherentimplblock, and looked at what it expands to —mem::taketo get ownership,redrop::enqueueto hand off the future. - Learned that a shared, bounded-concurrency pump is what keeps a burst of drops from
overwhelming anything, and that the
tokiofeature adds a background task that drains it continuously. - Pulled the concurrency limit out of code entirely, into
redrop.toml, loaded with a path that itself can be overridden by an environment variable. - Landed on
shutdown()as the one call that actually guarantees everything finished.
Where to go from here
- The
showcase/crate in the repository is the complete, runnable version of everything in this tutorial — read it end to end now that you know what each piece is doing. - The
redropcrate's own top-level documentation covers the same ground in reference form, useful once you're past the "first time" stage and just need to look something up.
Thanks for reading slowly. That's genuinely the best way through this kind of material.