Cron jobs
Some work has to be done regularly and without a person: deleting old records, updating currency rates, sending reports. Magento has a scheduler (cron) for that: a module describes a job and its run time in an XML file and writes the code in a plain class.
Where the files live
| File | What is in it |
|---|---|
etc/crontab.xml | The list of jobs and the schedule |
Cron/CleanReviews.php | The job class |
Both files are created by hand.
app/code/Acme/Hello/
├── Cron/
│ └── CleanReviews.php new file
└── etc/
├── crontab.xml new file
└── module.xmlThe job class
The job deletes reviews without text that are more than a year old:
// app/code/Acme/Hello/Cron/CleanReviews.php
namespace Acme\Hello\Cron;
use Acme\Hello\Model\ResourceModel\Review as ReviewResource;
use Psr\Log\LoggerInterface;
class CleanReviews
{
public function __construct(
private ReviewResource $resource,
private LoggerInterface $logger,
) {}
public function execute(): void
{
$deleted = $this->resource->getConnection()->delete(
$this->resource->getMainTable(),
[
'created_at < ?' => date('Y-m-d H:i:s', strtotime('-1 year')),
'content IS NULL',
],
);
$this->logger->info('Old reviews deleted: ' . $deleted);
}
}The class extends nothing: all it needs is a public method for the scheduler to call. It deletes the rows with one query and writes their number to the log.
The schedule
<?xml version="1.0"?>
<!-- app/code/Acme/Hello/etc/crontab.xml -->
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Cron:etc/crontab.xsd">
<group id="default">
<job name="acme_hello_clean_reviews" instance="Acme\Hello\Cron\CleanReviews" method="execute">
<schedule>0 3 * * *</schedule>
</job>
</group>
</config>The acme_hello_clean_reviews job runs every day at three in the morning. The schedule tag holds five fields: minute, hour, day of month, month, day of week.
| Schedule | When it fires |
|---|---|
* * * * * | Every minute |
*/15 * * * * | Every 15 minutes |
0 * * * * | At the start of every hour |
0 3 * * * | Every day at 03:00 |
0 9 * * 1 | On Mondays at 09:00 |
Checking
To avoid waiting for the night, set the schedule to * * * * * while testing and run the scheduler by hand:
bin/magento cache:clean
bin/magento cron:run --group=default
bin/magento cron:run --group=defaultThe first run puts the job into the queue — the cron_schedule table — and the second one executes it. The line "Old reviews deleted" appears in the var/log/system.log file. In the cron_schedule table the job shows its status (pending, success, error) and the error text, if there was one.
Enabling the scheduler on a server
bin/magento cron:installThe command adds a line to the current user's system crontab that calls bin/magento cron:run every minute. Without this step jobs do not run at all, and neither do scheduled indexers or email sending. Check the result with the crontab -l command.
Message queues
The scheduler suits work done "by the clock". For work done "on an event" — sending an email after an order, passing an order to a warehouse — Magento has message queues. Code puts a short message into a queue and continues right away, while a separate background process (a consumer) picks messages up and handles them. A queue is described by the communication.xml, queue_topology.xml, queue_publisher.xml and queue_consumer.xml files and is stored in the database or in RabbitMQ. This is a topic for separate study; for now it is enough to know the tool exists.
Common mistake
A job is described correctly but does not run, and the cron_schedule table is empty. The cause is almost always the same: bin/magento cron:install was not run on the server, or the scheduler runs as a different user. Check crontab -l as the user PHP runs under.