Display a custom response during downtime

From EPrints Documentation
Jump to: navigation, search


See also Creating a Maintenance Page.

We were recently migrating our database from an old server to a new one - which required a dump + load of data (rather than a replication). This meant we had a period of 3 hours where EPrints wouldn't be accessible.

During this downtime, I wanted to display a useful message, with a '503 Service unavailable' HTTP response. This is how to achieve this using EPrints triggers:

NOTE if you are doing maintenance blocking the database, the method below will not work, as EPrints will complain about not being able to connect to the database before processing the trigger. If your maintenance will result in the database being offline (rather than read-only), the maintenance page should be delivered using Apache. Please see https://stackoverflow.com/questions/622466/how-to-put-apache-website-to-503-temporary-down for some examples).

  1. Create a file ~/archives/ARCHIVEID/cfg/cfg.d/a_MAINTENANCE.pl. The name of the file isn't important - but it should be alphabetically before any other config file that defined a URL_REWRITE trigger.
  2. Add the following to the file, altering the maintenance_allowed_ip, maintenance_retry_after and maintenance_page_html including ###REPO NAME###, Date/Time and contact e-mail address appropriately. I'd keep the html page quite simple, but with enough info to help a human. Remember to escape any single-quotes in the HTML block with a backslash e.g. BAD: we've; GOOD: we\'ve.:
# Set maintenance to 1 to respond with a 503 for requests, except those from the maintenance_allowed_ip.
$c->{maintenance} = 0;
$c->{maintenance_allowed_ip} = '127.0.0.1'; #set this to your IP address

# set to a date/time after your maintenance will have finished, 
# or a period (in seconds) that the maintenance will last for
$c->{maintenance_retry_after} = 'Mon, 14 Mar 2016 12:00:00 GMT'; #set to a date/time after your maintenance will have finished

use EPrints::Const;
$c->add_trigger( EP_TRIGGER_URL_REWRITE, sub {
        my( %args ) = @_;

        # args passed to EP_TRIGGER_URL_REWRITE are:
        #     request, lang, args, urlpath, cgipath, uri, secure, return_code
        my( $repository, $request, $return_code, $uri, $urlpath ) = @args{ qw( repository request return_code uri urlpath ) };

        #check we're in maintenance mode
        if( $repository->config( "maintenance" ) && $repository->config( "maintenance" ) == 1 ){
                # is there an IP we should allow through?
                # NB You might need to do other checks - e.g. X-Forwarded-For if you are behind a load-balancer
                # or for different versions of Apache (like here: https://github.com/eprints/eprints/issues/214)
                # if you're not sure, ask on the EPrints Tech list first!
                if( $repository->config( "maintenance_allowed_ip" ) && 
                    $repository->remote_ip eq $repository->config( "maintenance_allowed_ip" ) ){
                        return EP_TRIGGER_OK;
                }
                elsif( $uri !~ /^$urlpath\/(style|images)\// ) # allow image/stylesheet requests 
                                                               # through - so you can display a branded 503 page
                {
                        $request->custom_response( Apache2::Const::HTTP_SERVICE_UNAVAILABLE, $c->{maintenance_page_html} );
                        if( $repository->config( "maintenance_retry_after" ) ){
                            $request->err_headers_out->{'Retry-After'} = $repository->config( "maintenance_retry_after" );
                        }
                        # set the 503 response
                        ${$return_code} = EPrints::Const::HTTP_SERVICE_UNAVAILABLE;
                        # and don't process any more EP_TRIGGER_URL_REWRITE triggers.
                        return EP_TRIGGER_DONE;
                }
        }
} );

# A simple maintenance page - not using the template (which will probably link to various other pages that aren't
# accessible during the maintenance window
$c->{maintenance_page_html} = '<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<style>
body {
    font-family: sans-serif;
    margin: 3em;
}
footer {
    font-size: 80%;
    margin-top:2em;
}
</style>
<title>###REPO NAME### - Maintenance</title>
</head>
<body>
<header>
<img src="/images/sitelogo.png" />
<h1>###REPO NAME### - Maintenance</h1>
</header>
<section>
<p><strong>Date/Time</strong> We\'re currently doing things to the system.<br />
We\'ll be back soon!</p>
<p>If you have any questions, please contact someone@somewhere.blah</p>
</section>
<footer>
<p>###REPO NAME###</p>
</footer>
</body>
</html>';
  1. Do a ~/bin/epadmin test ARCHIVEID to make sure you haven't done anything silly in the config file.
  2. Do a ~/bin/epadmin reload ARCHIVEID and check that nothing's changed
  3. When you want to turn the maintenance response on, change set: $c->{maintenance} = 1; and reload the archive.
  4. Check that you can get in from the IP specified, and that you get the 503 response from other IPs.
  5. Do a graceful restart of Apache (e.g. apachectl graceful) - to stop the noisy 'repository had been reloaded' error messages.
  6. Do the maintenance.
  7. Change $c->{maintenance} = 0;, graceful restart Apache (e.g. apachectl graceful).
  8. Done!

If you want to include the default CSS files in the 503 page, include <link rel="stylesheet" type="text/css" href="/style/auto-3.3.14.css"> in the maintenance_html_page -> head section (update it for your version of EPrints!).