Maintenance mode for Symfony 2 applications

This article presents a nice an easy way of creating a maintenance mode for your Symfony 2 application.

Sometimes you have to lock a production server to perform a bigger update or restore it from a backup. You wouldn't want any users wandering around at that time. First of all they might accidentally break your update. Second, they might see something they shouldn't (like a lot of errors for example). This is where maintenance mode comes in handy.

Creating an event listener

Adding parameters

First of all, we're going to add two parameters to your app/config/parameters.yml file

parameters:
    maintenance: false #turn it to true to enable maintenance
    underMaintenanceUntil: tommorow 8 AM

Adding a service for the event listener

We're going to listen on the kernel.request event. Add the following to your app/config/services.yml file

services:
    acme.listener.maintenance:
        class: Acme\DemoBundle\Listener\MaintenanceListener
        arguments:
            container: "@service_container"
        tags:
            - { name: kernel.event_listener, event: kernel.request, method: onKernelRequest }

Creating the listener class

Save the following class as src/Acme/DemoBundle/Listener/MaintenanceListener.php

<?php

namespace Acme\DemoBundle\Listener;

use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\DependencyInjection\ContainerInterface;

class MaintenanceListener
{
    private $container;

    public function __construct(ContainerInterface $container)
    {
        $this->container = $container;
    }

    public function onKernelRequest(GetResponseEvent $event)
    {
        $maintenanceUntil = $this->container->hasParameter('underMaintenanceUntil') ? $this->container->getParameter('underMaintenanceUntil') : false;
        $maintenance = $this->container->hasParameter('maintenance') ? $this->container->getParameter('maintenance') : false;

        $debug = in_array($this->container->get('kernel')->getEnvironment(), array('test', 'dev'));

        if ($maintenance && !$debug) {
            $engine = $this->container->get('templating');
            $content = $engine->render('::maintenance.html.twig', array('maintenanceUntil'=>$maintenanceUntil));
            $event->setResponse(new Response($content, 503));
            $event->stopPropagation();
        }

    }
}

Creating the maintenance mode view

Create a twig file under your app/Resources/views directory and save it as maintenance.html.twig. Example view code below:

{% extends '::base.html.twig' %}
{% block title %}
    Maintenance -
    {{ parent() }}
{% endblock title %}

{% block styles %}
    {{ parent() }}
{% endblock %}

{% block content %}

<div>
<h1>Maintenance</h1>

<p><strong>The server is temporarily down for maintenance</strong><br />
The service needed to be locked to ensure data integrity during the update procedure<br />
{% if maintenanceUntil is not empty %} The service will be down until {{ maintenanceUntil }}. {% else %} We will resume normal operations as soon as possible. {% endif %}</p>
</div>
{% endblock content %}

Enabling and disabling maintenance mode

To enable maintenance mode set the maintenance parameter to true and optionally provide a timeframe in the underMaintenanceUntil parameter. To disable maintenance set the maintenance parameter to false.
Remember to clear the application cache after changing the parameter. The production environment won't get updated if you don't. In maintenance mode you can still access the app in the development and test environments.

Previous post