Upon a second look, I think the close should probably be async so that the messages are only returned after the last recv() finishes. I will update the original post accordingly. Hope this makes it less difficult.
The async_std Sender can see the channel's len() and capacity(), but unfortunately it's send() is infallible, so there is apparently no way to wait for errors happening on the receiving end. This API is still marked "unstable", but there are very good reasons (async-std/issues/212) they designed their Sender this way, so I don't think the send() can become fallible in the future.