The other day came across the nice task of moving a whole site and CMS to openshift. In case you don’t know what I’m talking about: Openshift is PaAS from RedHat that in contrast to other PaAS providers doesn’t use linux containers (like Heroku)

I like openshift over other providers because the free quota they provide is quite enough to start with small sites.

In the other hand, when you choose server your application from a PaAS instead a VPS/dedicated server, etc. you also should know there are hard limits.

While you can get cronjobs, the current support of the addon only let you schedule tasks to run minutely / hourly / daily / weekly / monthly but wont allow you to run cron expressions and have something like */3 * * * * You could get the current date and see if the divider matches your magic number…

Or you can come with something better…

Looking at packagist I found a nice project that will do all the dirty job for us: mtdowling/cron-expression is a component that parses cron expressions and let us match a date-time against such expression.

In order to make the script generic enough I also used ulrichsg/getopt-php but of course you could avoid this…

So cron-expression will take the parameters sent to the scripts using getopt-php, then parse the cron expression and run the command whenever the date matches the expression.

This is how my composer.json looked like

{
  "name": "site",
  "require": {
    "mtdowling/cron-expression": "1.0.*",
    "ulrichsg/getopt-php": "2.1.*"
  }
}

then I created an script (I called it) cron.php (original, ha!)

<?php

set_time_limit(0);

require __DIR__ . '/vendor/autoload.php';


$commandOpt = new Ulrichsg\Getopt\Option('c', 'command',
    Ulrichsg\Getopt\Getopt::REQUIRED_ARGUMENT);
$commandOpt->setDescription("the command to run");

$scheduleOpt = new Ulrichsg\Getopt\Option('s', 'schedule',
    Ulrichsg\Getopt\Getopt::REQUIRED_ARGUMENT);
$scheduleOpt->setDescription("the cron schedule to follow");

$getopt = new Ulrichsg\Getopt\Getopt(array(
      $commandOpt,
      $scheduleOpt));

try {
  $getopt->parse();
} catch (Exception $e) {
  echo $getopt->getHelpText();
  exit(1);
}

$command = $getopt->getOption('command');
$schedule = $getopt->getOption('schedule');

$cron = \Cron\CronExpression::factory($schedule);

if ($cron->isDue()) {
  passthru($command);
}

There are few things that are pretty obvious…for example I added passthru in order to run the command so the command’s output is sent back to the caller. I also removed some other stuff to make the example shorter.

The next step was to setup each task with their required schedule, I did so by creating a file into .openshift/minutely

something like

#!/bin/bash

env php /path/to/cron.php --schedule="*/3 * * * *" --command="php run_every_3_minutes.php"
env php /path/to/cron.php --schedule="*/15 4 * * *" --command="php another_script.php" // this will run every 15 minutes at 4am

Also, be aware that openshift imposes a 20 minutes limit for cronjobs and then scripts will be killed. In that case you should consider de-attaching the long-running process using nohup

That’s it…you now have a way to have more granular cronjobs in openshift using PHP