Skip to content

CRON Jobs

Nicholas K. Dionysopoulos edited this page Feb 15, 2024 · 5 revisions

Before you begin

Panopticon is only really useful when you can automate it. It can automatically check for Joomla! and extension updates, install Joomla! updates, send you emails, etc. This requires something to tell it to periodically execute the tasks in its automation queue. This something is CRON jobs.

This documentation page talks about setting up CRON jobs for processing the Panopticon tasks queue.

A CRON job always refers to executing a command line script in a predefined schedule. Some servers do not support real CRON jobs, they instead let you enter a URL. This is a pseudo-CRON, and it's supported to a certain extent but not recommended.

We will not explain how to create a CRON job on your site. This depends on your host and which hosting control panel software they are using. If unsure, ask your host. We cannot know how your particular host works. If we did, we'd have already put it in the documentation.

Paths to be replaced in the documentation

All CLI (command line) CRON examples use the paths /path/to/php and /dir/to/my/site. These paths are fake, they need to be replaced. The former path needs to be the absolute filesystem path to the PHP CLI executable. The latter path needs to be the absolute filesystem path to the root of your Panopticon installation. If unsure, ask your host. We cannot know what they are on your server; if we did, we'd have already put it in the documentation.

Mind the path to PHP

Please be cautious about what you use to replace /path/to/php. The PHP binary specified in that path MUST be the CLI binary of PHP. Panopticon's command line script will NOT work with the CGI/FastCGI script. To determine if you have the right script, run /path/to/php -v. You should get something similar to the following:

PHP 8.2.7 (cli) (built: Jun 15 2023 02:44:23) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.2.7, Copyright (c) Zend Technologies
    with Zend OPcache v8.2.7, Copyright (c), by Zend Technologies

Note the first line. Right after the version it states “(cli)”. This tells us it's the right binary.

If, instead you get something like the following then you are using the wrong binary:

PHP 8.2.7 (cgi-fcgi) (built: Jun 15 2023 02:44:31)
Copyright (c) The PHP Group
Zend Engine v4.2.7, Copyright (c) Zend Technologies
    with Zend OPcache v8.2.7, Copyright (c), by Zend Technologies

Note the first line. Right after the version it states “(cgi-fcgi)”. This is the WRONG binary. CGI / FastCGI can only be used for serving web pages. It has a different set of restrictions which makes it unsuitable for running command-line scripts.

Real (CLI) CRON

This is the preferred option when your host:

  1. supports real CRON jobs which can execute command-line scripts
  2. the maximum execution time for CRON jobs —in other words, the maximum CPU time as returned by ulimit -t— is at least 30 seconds
  3. you can schedule tasks to run every minute

What if this is not the case? If your host does not meet these criteria you should go to a different host. These criteria are reasonable for mid-range, fairly inexpensive hosting since the mid-2010s. Hosts which do not allow that are either trying to cram too many sites on a server, or their knowledge of setting up a server is stuck in the early days of web hosting back in the early 2000s. Either way, their artificial limitations would prevent you from using Panopticon correctly.

Create a new CRON job for the command

/path/to/php /dir/to/my/site/cli/panopticon.php task:run --loop

where /path/to/php and /dir/to/my/site are to be replaced as explained above.

Make sure the command runs every minute. That's the CRON expression * * * * * (there are five stars in this expression).

WARNING! Panopticon's automation will NOT run reliably if you use a different schedule for its CRON job. Its CRON job MUST run every minute.

Once you are sure that the CRON job runs correctly you may change that command line to read

/path/to/php /dir/to/my/site/cli/panopticon.php task:run --loop >/dev/null 2>&1

The >/dev/null 2>&1 part at the end of the command line suppresses all output, therefore the host's CRON service will no longer be sending you emails about the execution of the CRON jobs every minute.

CRON jobs on Windows

Windows does not have CRON jobs, it has the Task Scheduler. The functionality is equivalent, but in typical Microsoft fashion it turns a simple, straightforward job into an annoyingly long series of clicking through endless screens.

Note: The instructions below are written using an English (UK) version of Windows 11. Task Scheduler is unchanged since the Windows XP era. Therefore, chances are it will be the same in future versions of Windows. However, if you are using a non-English version of Windows the labels and, most importantly, searching for Task Scheduler will be different. If you are unsure, temporarily switch your computer's interface language to English (UK) to follow the instructions below.

First, run Task Scheduler. Press the Windows button on your keyboard and type Task Scheduler to find it; recent versions of Windows make it very hard to locate programmes in any other way.

From the left hand pane click on the Task Scheduler Library under "Task Scheduler (Local)".

On the right hand pane click on Create Task.

In the General tab enter the following:

  • Name: Panopticon Task Runner
  • Description: Runs Akeeba Panopticon tasks
  • Security options: Run whether user is logged on or not
    • Check the box "Do not store password. The task will only have access to local computer resources."
  • Hidden: checked

Click on the Triggers tab. Click on the New button.

  • Begin the task: On a schedule
  • Settings: Daily
  • Repeat task every: 1 minute (you have to type 1 minute yourself; it's not one of the drop-down options!)

Click on the OK button.

Click on the Actions tab. Click on New.

  • Action: Start a program
  • Program/script: your path to PHP, e.g. C:\PHP\PHP-8.3\php.exe
  • Add arguments: your path to Panopticon's CLIL script, followed by task:run --loop. For example C:\Sites\panopticon\cli\panopticon.php task:run --loop.

Click on the OK button.

Click on the Conditions tab.

Clear the "Start the task only if the computer is on AC power" check box.

Click on the Settings tab.

Find the setting "If the task is already running, then the following rule applies:" at the bottom and set it to "Run a new instance in parallel".

Click on OK to save your new task.

What does the --loop option do?

The task:run command of the CLI CRON script processes pending items in Panopticon's task queue. Once the queue is empty, the script exits. It will not run until the CRON service tells it to run again, something which can take the better part of a minute.

If a new task is added during this ‘dead’ time, it's not executed until the script runs again. This may be confusing for the user.

Imagine the following example:

  • 00:13:00 The script executes and finds two tasks to execute.
  • 00:13:07 The script has executed the two tasks and exits.
  • 00:13:23 The user clicks on a UI button to update Joomla! on a site.
  • 00:14:00 The script executes again, finds the new task, and starts the Joomla! update on the site, per the user's instructions.

From the user's perspective, nothing was happening between 00:13:23 and 00:14:00, a whole 37 seconds. They could see that the update is scheduled, but it was not starting. The user might get confused as to why nothing is happening, especially if they know that no other site is being updated at that point in time.

This is where the --loop option comes in. When this option is present, the script processes all pending tasks. When it sees that no other tasks are available it does not exit. It goes to sleep for 10 seconds. Then it checks for pending tasks again. This repeats until the script reaches the “Maximum Execution Time” configured in the System Configuration page which is typically longer than one minute. This means that the execution of the CLI CRON scripts overlaps and the dead time is limited to a few seconds instead of the better part of a minute.

Let's repeat our example with the --loop option.

  • 00:13:00 The script executes and finds two tasks to execute.
  • 00:13:07 The script has executed the two tasks and sleeps for 10 seconds.
  • 00:13:17 The script finds no tasks and sleeps for 10 seconds.
  • 00:13:23 The user clicks on a UI button to update Joomla! on a site.
  • 00:13:27 The script checks again for pending tasks and starts the Joomla! update on the site, per the user's instructions.

As you can see, the time between the user clicking on the button to schedule the update and the update starting has dropped from 37 seconds down to 4 seconds. It could be even less due to the overlapping of CRON executions. Let's repeat the example with two CRON scripts executing at the same time (Maximum Execution Time being 100 seconds):

  • 00:12:00 Script instance 1 executes and finds one task to execute.
  • 00:12:05 Script instance 1 finishes processing tasks and sleeps for 10 seconds.
  • 00:12:15 Script instance 1 finds no tasks and sleeps for 10 seconds.
  • 00:12:25 Script instance 1 finds no tasks and sleeps for 10 seconds.
  • 00:12:35 Script instance 1 finds no tasks and sleeps for 10 seconds.
  • 00:12:45 Script instance 1 finds no tasks and sleeps for 10 seconds.
  • 00:12:55 Script instance 1 finds no tasks and sleeps for 10 seconds.
  • 00:13:00 Script instance 2 executes and finds two tasks to execute.
  • 00:13:05 Script instance 1 finds no tasks and sleeps for 10 seconds.
  • 00:13:07 The script has executed the two tasks and sleeps for 10 seconds.
  • 00:13:15 Script instance 1 finds no tasks and sleeps for 10 seconds.
  • 00:13:17 Script instance 2 finds no tasks and sleeps for 10 seconds.
  • 00:13:23 The user clicks on a UI button to update Joomla! on a site.
  • 00:13:25 Script instance 1 finds the new task and starts the Joomla! update on the site, per the user's instructions.
  • 00:13:27 Script instance 2 finds no tasks and sleeps for 10 seconds.

Therefore, using the --loop option allows a single CRON job to offer a much more responsive experience and increase the number of tasks which can be handled by your Panopticon installation.

Busy installations will need more than one CRON job

PHP is a single-threaded language by design. This means that it can do one thing at a time; it cannot really do multiple things at the same time (at least not in the way most people would imagine parallel execution to work). This means that the CLI CRON script can only process one task at any given time. When it's done with one task it moves onto the next, and so on and so forth.

As you start using Panopticon to perform more and longer tasks for each site (for example, running backups and the PHP File Change Scanner are usually quite lengthy), or you use it for more sites there will simply be too much work to be handled by a single CRON job in a reasonable amount of time. Simply put, the available time to do things will be less than the time required to perform all tasks across all monitored sites. In this case you need to create more CRON jobs.

"Creating more CRON jobs" means that you need to create copies of the same CRON job you have already created. That's right. You can have the exact same command, running with the exact same once-a-minute frequency multiple times. Each instance is its own CRON job. And yes, they all run at around the same time (at least within the same couple of seconds from each other for reasons you don't need to care about).

There is no rule of thumb to how many CRON jobs you need. It all depends on how Panopticon is configured and how busy things get at the worst of times. It could be as little as one CRON job for every 30 sites or as much as one CRON job for every 2 sites. Since version 1.0.5, when Panopticon detects that your CRON jobs struggle to keep up it will warn you, which gives you a good hint that you need to create more CRON jobs.

The CLI CRON job script is designed to consume a minimal amount of memory, about 5MiB or less in most cases. This means that even a site on very memory–constricted shared server can easily run 10–15 CRON jobs without hitting any memory limits.

Web pseudo-CRON

Panopticon also provides a special URL which, when accessed, processes the task queue. This is documented in the software itself.

We do not recommend using this option.

Web requests usually have a stricter maximum CPU time usage limit than CLI scripts and there's also the timeout limits of PHP itself and the web server to take into account. Because of this restriction, there is no equivalent to the CLI CRON script's --loop option, which means that at the very least the URL can process less tasks than a real CLI CRON job in the same amount of time. On some hosts these limits may be too low (2 to 10 seconds), to the point that they become practically unusable for automating Panopticon with a web-based pseudo–CRON.

Web servers also tend to block an IP address which calls the same URL repeatedly. This means that you are likely unable to set up multiple web-based pseudo–CRON jobs. This prevents you from monitoring more than a small handful of sites.

Generally speaking, using the web pseudo-CRON is a bad idea. Don't do it. You will suffer.

How to run multiple CRON jobs at the same time

On some hosts you cannot set up the exact same CRON job more than once.

For example, on a cPanel host you may have set up the CLI CRON job /usr/bin/php /path/to/panopticon/cli/panopticon.php task:run to run every minute. If you try to create an identical CRON job, cPanel tells you that you have already set up a CRON job. Since Panopticon 1.1.0 there is a new option, --dummy to overcome this problem. The second CRON job you set up should have --dummy=2 at the end, i.e. /usr/bin/php /path/to/panopticon/cli/panopticon.php task:run --dummy=2. The third one should have --dummy=3 at the end, i.e. /usr/bin/php /path/to/panopticon/cli/panopticon.php task:run --dummy=3. And so on and so forth.

For Web CRON jobs you can simply append a URL parameter called dummy using the same idea. The second web CRON job should access the URL Panopticon gives you with &dummy=2 at the end. And so on and so forth.

The dummy option is ignored. It does absolutely nothing. Its sole function is to make every otherwise identical CRON job look different, so that your hosting software managing the CRON jobs will stop complaining that this CRON job already exists.

Clone this wiki locally