Problem/Motivation

If a site is in maintenance mode, and the Drupal page cache is on, cached pages can still be viewed.

Additionally, if the page cache is on during maintenance mode, visited pages that return the maintenance mode message will be cached, and will continue to show the maintenance mode page even after turning maintenance mode off, until the cache is cleared.

Proposed resolution

Put a check in drupal_page_is_cacheable(), so that if we are in maintenance mode, page caching is disabled.

Remaining tasks

None?

User interface changes

None.

API changes

None.

None.

Original report by @Kevin Hankens

Drupal should not cache the maintenance page and should not retrieve a cached page while in maintenance mode.

To replicate:

  • Turn on page caching for anonymous users
  • Visit the homepage as an anonymous user to ensure that it is inserted into page_cache
  • Put your site into maintenance mode
  • Visit the homepage again as an anonymous user and you will be able to see your homepage, but visiting any non-cached pages will show the maintenance mode page.

This also happens in the reverse, Drupal - while in maintenance mode - is able to cache the maintenance mode page. So, after coming out of maintenance mode, the cached maintenance page is displayed.

This is remedied by clearing the cache after going into and out of maintenance mode. However, it seems that while you are under maintenance, you should neither create nor retrieve cached pages.

This might be the same issue as: http://drupal.org/node/304190

This patch proposes that the function drupal_page_is_cacheable() should return false while the site is under maintenance.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

Kevin Hankens’s picture

Status: Active » Needs review

After thinking more about this and discussing with CrookedNumber it seems like the caching could be a desirable effect.

Caching the maintenance page would give a slight performance boost. Plus, delivering previously cached pages while in maintenance mode would make the site appear to be live to a good number of visitors - e.g. homepage viewers.

Perhaps the fix is to add a submit handler to system_site_maintenance_mode() that clears out the cache_page table when you go out of maintenance mode.

Thoughts?

kafitz’s picture

FileSize
641 bytes

It's true that, when the page caching is on for anonymous users and you put the site in maintenance mode, it's still possible to see cached pages as an anonymous user. Also when maintenance mode is turned off, some anonymous users will see, for a certain time, the maintenance page.

Personally I think that the maintenance mode can't be used to lightly and in this perspective it looks normal that, when there is no other option and you must put on the maintenance mode, every visitor sees the maintenance page immediatly. Kevin Hankens has an other conviction on that issue, so I think this is debatable.

Also the same logic when you go out of maintenance mode. When going out, every user must see the website immediatly. This issue makes sense. Kevin Hankes suggested to add a submit handler to system_site_maintenance_mode(). I aggreed and therefore I wrote a little patch that flush all caches when the administrator puts on/off the maintenance page.

Good or bad solution? Let me know...

kafitz’s picture

Apologies, wrong patch...

Here is the correct one.

Status: Needs review » Needs work

The last submitted patch, maintenance_flush_cache2.patch, failed testing.

kafitz’s picture

Apologies, again

mr.baileys’s picture

Status: Needs work » Needs review
Kevin Hankens’s picture

Personally, I'm not convinced that people want to flush all caches when they exit maintenance mode. After some more consideration, it seems a little heavy handed.

kafitz’s picture

True, it is a little heavy to flush all caches. On the other hand, when content is changed in maintenance mode, the user can immediately see the changes that has been made.

Also, I like your solution. But the problem I have is, after changes made in maintenance mode and putting maintenance mode off, that unchanged cached pages could be displayed.

edvanleeuwen’s picture

I support kafitz request for prohibiting the display of cached pages when in maintenance mode.

Emptying the cache when going in does the trick for me, but perhaps bypassing the cache during maintenance for non-admins would be a solution (although I do not know whether this makes it easier to implement).

edvanleeuwen’s picture

Other suggestion: put a button on the maintenance mode page to clear caches (automatically or by hand) and add a little explanation why this is important.

Furthermore, for now this is a difference in coping with cache with previous versions. Should that not be mentioned anywhere in the upgrade guide to prevent misunderstandings?

quantos’s picture

A minor caveat here is that I had no idea that Site Maintenance had a caching issue until trying to demo an admin-locked site to a client this morning with the unfortunate effect of leaving me locked out of the site while trying to demo my great new responsive site on ipads and mobiles - without having to login. Talk about embarrassing. My vote would go to some kind of forced clearance of the cache every time you go into or out of Maintenance. Surely, 99% of the time that's why site's are in Maintenance in the first place?

PROMES’s picture

Yesterday a customer called me: why is the site in maintenance mode? I need it to show to some important people. But the site wasn't in maintenance mode but the maintenance mode page was cached.
I had to spend some costly time finding out what's happening.

Why should pages being cached in maintenance mode anyway? Get rid of caching the maintanance page and nobody has to care about clearing one or more caches after setting the site online again!

andypost’s picture

Version: 7.x-dev » 8.x-dev
Issue tags: +Needs tests

SiteMaintenanceTest should be extended with checking for headers according #1990098: Avoid caching of pages containing debug info

Core fires 503 now in onKernelRequestMaintenanceModeCheck()

mkalkbrenner’s picture

ianthomas_uk’s picture

Personally, I'm not convinced that people want to flush all caches when they exit maintenance mode. After some more consideration, it seems a little heavy handed.

Why do people go into maintenance mode? Usually it's done when people are upgrading their Drupal site, so enforcing a cache clear is quite a good idea.

Are there other scenarios when you'd want to put your site into maintenance mode but wouldn't want to clear your cache? Maybe this needs to be an option when coming out of maintenance mode (defaulting to clearing the cache).

adammalone’s picture

Clearing the offending object from cache on a submit handler when coming out of maintenance mode sounds great in principal but my workflow for upgrading Drupal sites makes heavy use of Drush.

I put sites into and out of maint mode by using drush vset which would not invoke any additional submit handler to clear the cache. It also stands to reason that as Drupal is providing a server error http response (503), we should not be caching this for users.

It's my view that we should not cache the site when it's under maint mode and also ensure that no cached content is served to users (also solving #304190: Turning Site Offline Doesn't Occur Until Cache is Cleared).

In the interests of users who would like to be able to cache their site when it's in maint mode I suppose a variable (config in 8.x) could be used to ensure the site is cached. I'd be keen to take a look at this issue over the next few days and roll a patch!

ianthomas_uk’s picture

Is it even technically possible to disable the cache, and if so what performance impact would it have? I think Drupal is too dependent on it's cache to make this a viable option.

Possible solutions
- Disable only some parts of the cache (the bits closer to the user, e.g. disable page cache but leave the function registry). Leave the potential for problems with the parts that we are still caching.
- Ensure maintenance mode cache is separate from standard cache but automatically modifing cache keys. Would be slow going into maintenace mode and increase the size of the cache, but otherwise OK I think.
- Clear the cache when disabling maintenance mode, taking into account drush users by either introducing a new command or adding special behaviour to the mainteance_mode variable.

adammalone’s picture

Here's a very simple patch for 8.x that ensures pages do not get cached/cached pages do not get delivered when maintenance mode is on. Due to the fact that this check is in bootstrap.inc we can't employ some caching for users who can get on during maintenance mode.

My thoughts did switch to accommodate this however, in case changes are being made to the site, it'd be good for those making the changes to get uncached versions.

tstoeckler’s picture

I think it would be cool if we could have a MaintenanceModeBundle, similar to UpdateBundle, which simply sets all the services to the uncached versions. For the page cache that's currently not possible, so the patch in #18 might be a step in the right direction nonetheless.

tstoeckler’s picture

Oh, I of course mean MaintenanceModeServiceProvider, just like the current UpdateServiceProvider.

Cameron Tod’s picture

Status: Needs review » Needs work

I think the approach is sound and addresses the issue. Just a nitpicky code style review.

  1. +++ b/core/includes/bootstrap.inc
    @@ -992,9 +992,12 @@ function drupal_page_is_cacheable($allow_caching = NULL) {
    +  // We cannot check _menu_site_is_offline in bootstrap.inc as
    +  // menu.inc has not been loaded yet
    

    Needs a full stop at the end of the comment. I would also put in some explanation about why we are checking that the site is offline.

  2. +++ b/core/includes/bootstrap.inc
    @@ -992,9 +992,12 @@ function drupal_page_is_cacheable($allow_caching = NULL) {
    +  $site_offline = Drupal::config('system.maintenance')->get('enabled');
     
       return $allow_caching_static && ($_SERVER['REQUEST_METHOD'] == 'GET' || $_SERVER['REQUEST_METHOD'] == 'HEAD')
    -    && !drupal_is_cli();
    +    && !drupal_is_cli() && !$site_offline;
    

    Do we need a variable here? Can we just call Drupal::config inline?

Cameron Tod’s picture

I think the approach is sound and addresses the issue. Just a nitpicky code style review.

  1. +++ b/core/includes/bootstrap.inc
    @@ -992,9 +992,12 @@ function drupal_page_is_cacheable($allow_caching = NULL) {
    +  // We cannot check _menu_site_is_offline in bootstrap.inc as
    +  // menu.inc has not been loaded yet
    

    Needs a full stop at the end of the comment. I would also put in some explanation about why we are checking that the site is offline.

  2. +++ b/core/includes/bootstrap.inc
    @@ -992,9 +992,12 @@ function drupal_page_is_cacheable($allow_caching = NULL) {
    +  $site_offline = Drupal::config('system.maintenance')->get('enabled');
     
       return $allow_caching_static && ($_SERVER['REQUEST_METHOD'] == 'GET' || $_SERVER['REQUEST_METHOD'] == 'HEAD')
    -    && !drupal_is_cli();
    +    && !drupal_is_cli() && !$site_offline;
    

    Do we need a variable here? Can we just call Drupal::config inline?

adammalone’s picture

Status: Needs work » Needs review
FileSize
766 bytes

Good points, here's a reroll!

Fabianx’s picture

Looks good to me, but still needs Tests.

Cameron Tod’s picture

Status: Needs review » Needs work

The last submitted patch, drupal8.no-cache-maintenance-mode.system.1032936-25.patch, failed testing.

Cameron Tod’s picture

Let's try again...

Status: Needs review » Needs work

The last submitted patch, drupal8.no-cache-maintenance-mode.system.1032936-27.patch, failed testing.

adammalone’s picture

I'm seeing the test fail locally as well with the issue being that the browser is delivering a 304 not modified and displaying the page - even if I alter index.php which makes me think simpletest is doing the same thing.

This isn't necessarily a bad thing however, as it ensures the site appears up. What would be an even better thing to test would be that after receiving a maintenance page, the anonymous user sees the site again immediately after maintenance mode is switched off.

I'll look at altering the patch to provide that functionality today.

Cameron Tod’s picture

Issue tags: +London_2013_October

Adding tag.

Cameron Tod’s picture

Issue summary: View changes

Added standard summary template.

adammalone’s picture

New tests with slightly altered functionality, checking that maint pages are not cached.

adammalone’s picture

Status: Needs work » Needs review

Status: Needs review » Needs work
neclimdul’s picture

put your failure patch first to keep the issue green

Fabianx’s picture

Status: Needs work » Reviewed & tested by the community

RTBC, looks great to me!

sun’s picture

Status: Reviewed & tested by the community » Needs review

The test only covers cached page responses after disabling the maintenance mode, but not before enabling it?

→ After creating the node, log out, and access the node page with the anonymous user, so that it is cached. Then log the admin user back in, enable maintenance mode, log back out, and assert that the node page does not show the cached page for anonymous users.

(The remainder of the test makes sense.)

Charles Belov’s picture

These are two separate issues.

Ideally, it would be an option to allow the admin to choose whether or not to serve cached pages while the website is down.

But we would definitely want visitors to experience a short cache time for maintenance pages.

The catch is, if I understand correctly, that it's not safe to clear Varnish cache sitewide on a busy site, that it could bring the site down. If that is correct, we'd need a way just to clear the cached maintenance pages as opposed to the entire Varnish cache.

A temporary workaround while waiting for this patch to be implemented would be to manually set both cache settings to 1 minute just before going into maintenance mode and restoring the settings, e.g., to 15 minutes and 6 hours if that's what your site is using, immediately after coming out of maintenance mode. But you'd have to remember to do both. Alas, there appears to be no reaction rule which would allow this.

Alternatively, the caching of maintenance pages would be a separate setting from the caching of other pages.

mgifford’s picture

Status: Needs review » Needs work
mgifford’s picture

Assigned: Cameron Tod » Unassigned

Making this unassigned as it's been a year or more...

Fabianx’s picture

adammalone’s picture

adammalone’s picture

Wim Leers’s picture

Component: cache system » base system
Status: Needs work » Closed (duplicate)

AFAICT #2453351: Maintenance mode message ends up in page cache, served endlessly covered all things that need to be tested. Hence marking this as a duplicate.

Berdir’s picture

Component: base system » cache system
Status: Closed (duplicate) » Needs work

Not sure about #36.

That's about the opposite, whether enabling the maintenance mode should still show cached patches or not? In a way, I think that's actually a feature. If we still have a cached page, there's no harm done in showing that instead of the maintenance message?

If you have varnish in front of your site, then you likely even want to force that to return expired pages, so I'd say that's a feature, not a bug?

Berdir’s picture

Component: cache system » base system
Status: Needs work » Closed (duplicate)

Didn't want to change status.