Some history: I believe a long time ago, publishing API on crates.io was synchronous -- it only return an http response to cargo publish after publishing was fully finished. This then was changed on serve side to async publishing for some technical reason I don't remember.
I'd like to share my script for this: gist (requires cargo-add). Usage: sync_publish path_to_crate -f
It creates a temp package using the published crate as a dependency and waits until cargo can successfully generate a lock file for it. That usually takes a few seconds.
As a bonus, it skips already published versions, so you can run it for every package in your workspace (in an outer script), and it will only try to publish the crates when you bump their versions.
While I haven't tried it myself, it looks like cargo-release has a similar loop which updates metadata, looks for the published crate, instead of trying to create a temp package in its wait_for_publish function. There is a sleep there, but just for a second presumably to avoid being too busy.
Assuming we don't want to make changes to how crates.io the wait_for_publish() function mentioned by @ratmice is probably the best you can do.
The underlying problem is that we don't have a mechanism to let the server asynchronously push events down to us. One possible idea is for crates.io to gain a pub-sub service where you can subscribe to be notified about certain events, then cargo-release and friends would temporarily subscribe to notifications for just that package, do the release, then go to sleep until crates.io says it's been released.
How does docs.rs know when a new package has been published so it can generate docs? Is it just polling for changes every X minutes, too?
Currently yes, every minute (maybe slightly longer, I didn’t check) it updates a local index clone and checks if there are new crates. There’s plans to move that to a webhook, but that’d be a rust-lang internal infrastructure thing.