Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

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

FileWhat is in it
etc/crontab.xmlThe list of jobs and the schedule
Cron/CleanReviews.phpThe job class

Both files are created by hand.

app/code/Acme/Hello/
├── Cron/
│   └── CleanReviews.php        new file
└── etc/
    ├── crontab.xml             new file
    └── module.xml

The 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.

ScheduleWhen it fires
* * * * *Every minute
*/15 * * * *Every 15 minutes
0 * * * *At the start of every hour
0 3 * * *Every day at 03:00
0 9 * * 1On 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=default

The 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:install

The 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.

Thanks for reading!

Donate to the site — we work hard for you.