"have a distributed cache of JWTs that have been revoked. The nice thing about JWTs is that they expire, so you can sweep your cache and drop tokens that have expired every night or whenever."
Every cache has TTL, so you just set the TTL of the entry to the expiration date of the token you are caching. No need for nightly cleanups.
I'm not sure cache was the right word in the parent post-- you don't want to use a cache (at least one with LRU/bounded size) to store revocation without a backing store, or else the revocation could get pushed out of the cache and become ineffective. The backing store (likely a DB) would require such cleanups once the revocation record is no longer relevant.
I would challenge your assumption. Unless you absolutely need to have 100% durable, consistent revocations for some reasons, something like memcached is perfect here as the worst case scenario in case of a failure is a slight, temporary degradation in security without any visible user impact or operations nightmare (ie restoring backups). This assumes that your token lifetime is reasonably short (at least for access tokens), refresh tokens are a different story but only need to be tracked at the authn service, not globally.
If the revocation use case is soft, then totally fair. But if the application is potentially dangerous and the user says "Sign out all devices", I think that should be a deterministically successful operation. Similarly, if there is a compromised account in an organization, I'd like to be confident that revoking all credentials was successful.
Revocation of tokens can be done for a simple logout operation, in which case the stakes are low, but more often it is the "pull the fire alarm and get that user out", and in that case it should be reliable.
Every cache has TTL, so you just set the TTL of the entry to the expiration date of the token you are caching. No need for nightly cleanups.