First, a couple contextual comments on all this:
- You are probably getting a 403 (Access Denied) message instead of a 404 (Not Found) message when visiting a previously unpublished page that was cached.
- The method call that you referenced (
entity_get_controller('node')->resetCache(array($node->nid))
) within node_save()
does not have anything to do with the page cache, and is instead related to the static entity cache, which only has an impact on the current request. However, you are certainly correct that Drupal makes an effort to clear the page cache upon a node save, but that happens in node_form_sumbit() when it calls cache_clear_all()
at the end.
- The cache clearing methods in Drupal are very strange and non-intuitive. I've seen entire threads erupt in passionate arguments and misunderstandings over the workings of
cache_clear_all()
and DrupalDatabaseCache::clear()
.
If cache_clear_all()
is called without any arguments, as is the case on a node update, only the page and block cache bins will be targeted for clearing. That's fine as it's presumably the page cache that matters in your case, but as you noted the "Minimal Cache Lifetime" will be respected. The exact logic used to respect this "Minimal Cache Lifetime" (in DrupalDatabaseCache::clear()
) might make your mind melt... but that's an aside.
As indirectly noted in another answer, you can call cache_clear_all()
with a specific node URL to force the needed page_cache entry to be cleared. This will do the job independent of the "Minimal Cache Lifetime" which, IMHO, is quite non-intuitive. Thankfully there are tools that account for all this non-intuitive logic for us, like the Expire module. Not only does it have the ability to target certain actions in Drupal (such as a node update), and clear the cache when they happen, but it will do it in such a way that the "Minimal Cache Lifetime" is factored-in and bypassed as needed. There is an old issue thread here that seems to talk about this a little more.
Also, if you have another page cache active (Varnish, Boost, etc.) they may be suspect too, and may be returning a previously cached version of the request independent of the local Drupal page cache. If you have an external cache like this in place you should check its own settings along with the the core "Expiration of cached pages" setting (just below the "Minimal Cache Lifetime" setting). Once again, the Expire module can help here as it also integrates with external caches to sync their expirations with Drupal updates.