We have moved our forum to GitHub Discussions. For questions about Phalcon v3/v4/v5 you can visit here and for Phalcon v6 here.

Maintenance mode - redirect/ forward all requests

Hi all,

I'd like to have a way to switch my phalcon-based app to a maintenance mode. That means I want all the requests to land on the same "maintenance controller" if a "maintenance" constant is set to true in my boostrap.

The only way I've found so far is to overwrite my router, just before building the \Phalcon\Mvc\Application() , removing all the usual routes.

Isn't there a better way ? Some built-in router functions maybe ?

Thanks

this can be done quite easily. In your bootstrap file just redirect everything to your maintenance page

$response = new \Phalcon\Http\Response();
$response->redirect('maintenance/index');
$di->set('response', $response);

https://docs.phalcon.io/en/latest/reference/response.html#making-redirections



24.8k

Hi Stefan,

Thanks for the reply. I would have preferred something like a catchall-ish function on the dispatcher, but I guess I can live with a redirect. Cheers

you might be able to set a Dispatch Loop Event to achieve the same thing

https://docs.phalcon.io/en/latest/reference/dispatching.html



24.8k

I've tried to use the dispatcher loop, followed the examples but I can't get it to work (or it doesn't change anything)... I've got a releatively complex router (multi-modules + optional language parameter) and I can't seem to get a proper "catchall" to deal with bad urls.

For instance, if I try to access a non-existant module, the $router->notFound() function catches it.
(https://my.domain.name/sdadsad or https://my.domain.name/sdadsad/asdsadsad or https://my.domain.name/sdadsad/asdsadsdsaas/sadsadasdsa)

But as soon as a module is specified, the errrors are not caught anymore: ==> https://my.domain.name/frontend/asdad : "handler class cannot be loaded" ==> https://my.domain.name/frontend/index/asdad : "Action 'aSas' was not found on handler 'index'"

I don't know if that helps, but here is my router:

--

$di['router'] = function() use ($___asConfig) {

//Set to false to be able to use the notFound route
$router = new \Phalcon\Mvc\Router(false);
$router->setDefaults(array('module' => 'frontend',    'controller' => 'index', 'action' => 'index'));

//Catch all
$router->notFound(array('module' => 'frontend', 'controller' => 'deadend', 'action' => 'notfound'));

//App root and default behaviour
$router->add('/', array('module' => 'frontend', 'controller' => 'index', 'action' => 'index'));
$router->add('/{lang:([a-z]{2}([_\-][[:alnum:]]{1,8})?)}', array('module' => 'frontend', 'controller' => 'index', 'action' => 'index'));

//prepare a group to manage the same routes including the language param
$withLocale = new \Phalcon\Mvc\Router\Group();
$withLocale->setPrefix('/{lang:([a-z]{2}([_\-][[:alnum:]]{1,8})?)}');
$withLocale->add('/', array('module' => 'frontend', 'controller' => 'index'))->setName('local-lvl-1');

//For each available module, add a set of generic and locale routes + the customs module routes
foreach($___asConfig['modules'] as $sModuleName => $asModuleConf)
{

//First: add generic routes for each module

$router->add('/'.$sModuleName, array('module' => $sModuleName, 'controller' => 'index')); $router->add('/'.$sModuleName.'/:controller' , array('module' => $sModuleName, 'controller' => 1)); $router->add('/'.$sModuleName.'/:controller/:action', array('module' => $sModuleName, 'controller' => 1, 'action' => 2)); $router->add('/'.$sModuleName.'/:controller/:action/:params', array('module' => $sModuleName, 'controller' => 1, 'action' => 2, 'params' => 3));

//Second step: adding the same routes, adding the locale parameter // use withLoacl Group, and change param indexes due to regExp at the group level)

$withLocale->add('/'.$sModuleName, array('module' => $sModuleName, 'controller' => 'index'))->setName('local-lvl-2'); $withLocale->add('/'.$sModuleName.'/:controller' , array('module' => $sModuleName, 'controller' => 3))->setName('local-lvl-3'); $withLocale->add('/'.$sModuleName.'/:controller/:action', array('module' => $sModuleName, 'controller' => 3, 'action' => 4))->setName('local-lvl-4'); $withLocale->add('/'.$sModuleName.'/:controller/:action/:params', array('module' => $sModuleName, 'controller' => 3, 'action' => 4, 'params' => 5))->setName('local-lvl-5');

}

$router->mount($withLocale);    
return $router;

};

--

Cheers



24.8k

OK, solved half my problem. In the multi-module example I used as a base, the module.php files were overwritting the dispatcher instead of simply setting up the module namespace.

I'll try to find a way to force the dispatcher to send every request to my maintenance controller now. :)



959

Too complicated, we should develop something like laravel comand-line tool.

In laravel,

To enable maintenance mode, simply execute the down Artisan command:

php artisan down

To disable maintenance mode, use the up command:

php artisan up

This is the best solution i think.

How to do this?

Hi bnfan,

I've taken a different approach now, I think the optimal option is to overwrite the router at the end of your boostrap. It's easy, in a single place (vs in each module), easy to maintain, and safe.

First, store a maintenance flag the way you want in a config file, cache (redis/memcache), db... based on your architecture. Then you load your app normally, and check this flag at the end of your config/boostrapping (anywhere before the dispatcher) Finally, if the flag is on, you simply overwrite your router service with a single catchhall route to the maintenance module /page.

If you want a cli command like laravel, you just need to implement phalcon-cli and create a task turn the flag on/off. I don't know if it's the best solution, but that works well for me.

Too complicated, we should develop something like laravel comand-line tool.

In laravel,

To enable maintenance mode, simply execute the down Artisan command:

php artisan down

To disable maintenance mode, use the up command:

php artisan up

This is the best solution i think.

How to do this?



959

Thank you for sharing your ideas, one config flag to control the router looks good too.

I still hope there is one official solution from Phalcon forum since this is a very common requirement.

How to overrite the router service, do you mean add some logic in /config/routes.php file? That may looks weird.

Hi bnfan,

I've taken a different approach now, I think the optimal option is to overwrite the router at the end of your boostrap. It's easy, in a single place (vs in each module), easy to maintain, and safe.

First, store a maintenance flag the way you want in a config file, cache (redis/memcache), db... based on your architecture. Then you load your app normally, and check this flag at the end of your config/boostrapping (anywhere before the dispatcher) Finally, if the flag is on, you simply overwrite your router service with a single catchhall route to the maintenance module /page.

If you want a cli command like laravel, you just need to implement phalcon-cli and create a task turn the flag on/off. I don't know if it's the best solution, but that works well for me.

Too complicated, we should develop something like laravel comand-line tool.

In laravel,

To enable maintenance mode, simply execute the down Artisan command:

php artisan down

To disable maintenance mode, use the up command:

php artisan up

This is the best solution i think.

How to do this?

You just need to overwrite your router (di service). Find below a basic example.

if(APP_MAINTENANCE)
{
  $di->remove('router');
  $di->setShared('router',  function() use ($config) 
  {
            $router = new \Phalcon\Mvc\Router(false);
            $router->setDefaults(array('module' => 'sgn', 'controller' => 'deadend', 'action' => 'maintenance'));
            $router->notFound(array('module' => 'sgn', 'controller' => 'deadend', 'action' => 'maintenance'));
            return $router;
  });
}

But you can add all the routes you want available during maintenance -- if any.



959
edited Sep '16

Good idea, I know how to do it.

My solution is defining one env variable in .env file, so switch the whole site to maintenance mode just need one character change.

It's very convenient, thank you for your code, it saves me tons of time, I only use 10 minutes to make it work!

Cheers!

You just need to overwrite your router (di service). Find below a basic example.

if(APP_MAINTENANCE)
{
 $di->remove('router');
 $di->setShared('router',  function() use ($config) 
 {
          $router = new \Phalcon\Mvc\Router(false);
          $router->setDefaults(array('module' => 'sgn', 'controller' => 'deadend', 'action' => 'maintenance'));
          $router->notFound(array('module' => 'sgn', 'controller' => 'deadend', 'action' => 'maintenance'));
          return $router;
 });
}

But you can add all the routes you want available during maintenance -- if any.