How to setup upstart: When Cron isn’t just enough

Reaching the limits of Cron

If you’re reading this blog post on account of the title, hopefully you already have a good understanding of what Cron is and you may well also be aware of some of it’s limitations. There are some situations when Cron use simply becomes impractical; the Cron minimum timeout of 1 minute can be prohibitively long to wait, rendering Cron an unhelpful tool for that particular project or situation.

In such moments I use Linux Upstart. It can run your code without a timeout at all or you can choose to set the timeout that you need.

Setting up Upstart

It’s very simple to set this up. To make a Symfony command I use daemonizable-command and write something like this:

namespace …\Command;
use Wrep\Daemonizable\Command\EndlessContainerAwareCommand;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
class UpdateCommand extends EndlessContainerAwareCommand {
protected function configure() {
parent::configure();
$this
->setName(‘<some name>')
->setDescription(‘<some description>')
->setHelp( "Use -q to suppress all output \n
Use --run-once to only run the command once, usefull for debugging \n
Use --detect-leaks to print a memory usage report after each run, read more in the next section" )
->setTimeout(0.5); //set timeout what your need
}
protected function execute(InputInterface $input, OutputInterface $output)
{
// here your code, if you need more timeout in some cases use “sleep(<time>)”
}
}
view raw gistfile1.txt hosted with ❤ by GitHub

Configuration

After that you’ll need to add an Upstart configuration file in Ubuntu.

The file extension should be “conf” eg,“project-task.conf”. Put the file into /etc/init/ or $HOME/.init/

description “<some description>"
author “<autor name, email etc.>”
start on (local-filesystems and net-device-up)
stop on shutdown
console log
respawn
respawn limit 5 60
exec project-url/app/console <commend name> -e prod —no-debug
view raw gistfile1.txt hosted with ❤ by GitHub

You can find more configurations here.

Control

Now you can control your command like a Ubuntu service:
service <project-task> status/stop/start/restart

Bonus

And for more usability I’ve written a small task for checking the status of and restarting these Upstart tasks. This one’s run by cron 🙂

class DaemonCheckCommand extends ContainerAwareCommand {
protected function configure() {
parent::configure();
$this
->setName('daemon-check')
->setDescription('Check daemons if it crased restarted it');
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$status= false;
$check = `echo ‘<password for this sudo user >' | sudo -S status <task name>`;
if ( strpos($check, 'start/running') === false ) {
$startingCheck = `echo '<password for this sudo user >' | sudo -S start <task name>`;
if ( strpos($startingCheck, 'start/running') === false ) {
$status .= "fail to start <task name> \n";
} else {
$status .= "restarted <task name> \n";
}
}
if ( $status ) {
$to = array(
'email' => ‘name',
…..
‘email-n' => ‘name-n'
);
$message = \Swift_Message::newInstance()
->setSubject('Project daemon crashed')
->setFrom(array('support@project.com' => 'Project'))
->setTo($to)
->setContentType("text/html")
->setBody(date('Y-m-d H:i') ."\n". $status);
$this->getContainer()->get('mailer')->send($message);
}
$this->getContainer()->get( 'logger' )->err('---Daemon Check = ' . ($status ? $status : (date('Y-m-d H:i') . ' working')) );
return $status;
}
}
view raw gistfile1.txt hosted with ❤ by GitHub

I hope this makes your life easier 😉