DEV Community

Cover image for Cron Jobs in Magento 2: How to Adjust Schedules and Cron Groups Seamlessly
Vladyslav Podorozhnyi πŸ‡ΊπŸ‡¦ 🌻 for run_as_root GmbH

Posted on • Edited on

Cron Jobs in Magento 2: How to Adjust Schedules and Cron Groups Seamlessly

Introduction

Hello!

In today's article, I'll cover a topic that's not too tricky, but can be a bit annoying without some useful tips. Specifically, we'll dive into Magento 2 ( Mage-OS / Adobe Commerce ) to discuss cron jobs, their configurations, and the process of rescheduling them and altering their execution group.

You might wonder, why bother changing the schedule or group of a cron job? Let's find out.

Why Adjust the Cron Schedule?

Occasionally, a cron job might execute too frequently, leading to server load issues or even deadlocks. On the other hand, if it doesn't run often enough, you could be left waiting for emails that take an hour to send. This scenario becomes particularly tricky when these cron jobs are associated with third-party extensions.

Let's imagine we are using 3rd party Feed and Mailing extensions, and we are not OK with their cron jobs schedule.

How can you modify the execution patterns of these cron jobs without tampering with the third-party code directly? By implementing changes in your own codebase – your module. Let's explore this next.

Rescheduling Cron Jobs

Let's have a look at the cron job of the Feed extension feed_generation.

Here is its definition:

<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="feed_generation" instance="\Feed\Cron\FeedGenerator" method="execute">
            <schedule>* * * * *</schedule>
        </job>
      ...
    </group>
</config>
Enter fullscreen mode Exit fullscreen mode

Executing every minute, this job can impose a significant server load. We certainly don't need a new feed every 60 seconds!

To modify its frequency, we'll craft a module, Devto_ChangeFeedSchedule, and incorporate an etc/config.xml file within.

So, the structure would look like this:

Devto_ChangeFeedSchedule/
β”‚
β”œβ”€β”€ etc/
β”‚   β”œβ”€β”€ config.xml      # our config file
β”‚   └── module.xml      
β”‚
β”œβ”€β”€ registration.php    
β”‚
└── composer.json       
Enter fullscreen mode Exit fullscreen mode

The etc/config.xml should contain:

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Store:etc/config.xsd">
    <default>
        <crontab>
            <default> <!-- cron group -->
                <jobs>
                    <feed_generation> <!-- job name -->
                        <schedule>
                            <cron_expr>0 * * * *</cron_expr> <!-- new cron execution schedule -->
                        </schedule>
                    </feed_generation>
                </jobs>
            </default>
        </crontab>
    </default>
</config>
Enter fullscreen mode Exit fullscreen mode

And last but not least - add sequence into etc/module.xml to declare dependency over Feed module and configs apply order:

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
    <module name="Devto_ChangeFeedSchedule" >
        <sequence>
            <!-- makes Devto_ChangeFeedSchedule configs be applied after Feed extension configs -->
            <module name="Vendor_FeedExtesnion"/>
        </sequence>
    </module>
</config>
Enter fullscreen mode Exit fullscreen mode

Once the module Devto_ChangeFeedSchedule is activated and the cache cleared, your new job schedule will take effect - run every hour but not a minute.

But what about cron groups? Let's delve into that next.

The Need to Change Cron Group

Imagine we're still working with the Feed and Mailing third-party extensions. These extensions utilize distinct cron groups, each operating as an isolated process. Thanks to this, cron groups can run concurrently/parallely, using individual processes.

Now, suppose these two cron jobs conflict, resulting in data inconsistencies in the Feed and Emails. Worse yet, deadlocks can crop up. You might ask, "Why the deadlocks?"

Well, imagine these extensions read & write the same table, say sales_order_item. When they run simultaneously, the stage is set for potential deadlocks. πŸ€·β€β™‚οΈ

If only these jobs were executed sequentially! By relocating them to a shared group, you can ensure they no longer run in parallel.

Altering the Cron Job's Group

A straightforward (though not perfect) solution would be to transfer the Mailing extension's cron job to the default group, where the Feed extension's job resides. Here's the Mailing cron job definition:

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Cron:etc/crontab.xsd">
    <group id="mailing_extension"> <!-- mailing cron group -->
      ...
        <job name="send_mails_from_mailing_extension" instance="\Mailing\Cron\SendMailsCron" method="execute">
            <schedule>*/20 * * * *</schedule>
        </job>
      ...
    </group>
</config>
Enter fullscreen mode Exit fullscreen mode

However, a small, non-intuitive trick is essential here: Simply changing the group by redefining crontab.xml won't work. Instead, you need to craft a new cron job while deactivating the old one. This step is necessary since crontab.xml configurations (especially groups) can't be overridden, only augmented.

For instance, merely defining the send_mails_from_mailing_extension cron job in the default group would make it run in both the default and mailing_extension groups.

To disable send_mails_from_mailing_extension, an easy trick is to schedule it for February 30thβ€”a date that doesn't exist!

nerd fact πŸ€“: actually February 30 happened in Sweden in 1712

Following our earlier approach, we'd add the following content to the etc/config.xml in our module, Devto_ChangeMailingJobGroup:

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Store:etc/config.xsd">
    <default>
        <crontab>
            <default>
                <jobs>
                    <!-- Disable cron execution by scheduling it to Feb 30th. -->
                    <send_mails_from_mailing_extension>
                        <schedule>
                            <cron_expr>0 0 30 2 *</cron_expr>
                        </schedule>
                    </send_mails_from_mailing_extension>
                </jobs>
            </default>
        </crontab>
    </default>
</config>
Enter fullscreen mode Exit fullscreen mode

Next, define a NEW cron job in the default group:

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Cron:etc/crontab.xsd">
    <group id="default"> <!-- default cron group -->
      ...
        <!-- added devto prefix to cron name -->
        <job name="devto_send_mails_from_mailing_extension" instance="\Mailing\Cron\SendMailsCron" method="execute">
            <schedule>*/20 * * * *</schedule>
        </job>
      ...
    </group>
</config>
Enter fullscreen mode Exit fullscreen mode

And do not forget to add Mailing module sequence into etc/module.xml:

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
    <module name="Devto_ChangeMailingJobGroup" >
        <sequence>
            <!-- makes Devto_ChangeMailingJobGroup configs be applied after Mailing extension configs -->
            <module name="Vendor_MailingExtesnion"/>
        </sequence>
    </module>
</config>
Enter fullscreen mode Exit fullscreen mode

After all changes, the module structure should look like this:

Devto_ChangeMailingJobGroup/
β”‚
β”œβ”€β”€ etc/
β”‚   β”œβ”€β”€ config.xml      # our config file
|   β”œβ”€β”€ crontab.xml     # our crontab definition file  
β”‚   └── module.xml      
β”‚
β”œβ”€β”€ registration.php    
β”‚
└── composer.json       
Enter fullscreen mode Exit fullscreen mode

Once Devto_ChangeMailingJobGroup is active and the cache refreshed, the send_mails_from_mailing_extension job will be disabled. Meanwhile, its counterpart, devto_send_mails_from_mailing_extension, will operate in the default cron group alongside the Feed cron job.

A Word of Caution on the Default Group

It's vital to recognize that Magento's native cron jobs already densely populate the default cron group. Overloading it might cause "traffic jams" if:

  1. Jobs have lengthy runtimes: If your tasks take too long to finish, they could end up waiting in line, slowing things down.
  2. Overfrequent Scheduling: Setting jobs to run too often can result in backlogs and potential overlaps.
  3. Overpopulation: Filling the group with too many tasks, even if they are quick, might overwhelm the system.

So, while the default group is convenient, treat it like a city's main highway during rush hour. It can handle a lot, but there's a limit before things get clogged. If you have too many heavy tasks or they're scheduled too frequently, you'll likely end up with delays.

In short, be mindful of the workload you're placing on the default group and consider creating your own cron groups to avoid conflict of processes.

Conclusion

And that's the lowdown on Magento's cron jobs, how to shuffle their schedules, and adjust their groups without diving into third-party code directly. With the knowledge you've gathered here, tweaking those pesky cron jobs should be much easier 😊

Thank you for reading!

Top comments (3)

Collapse
 
novikor profile image
Maksym Novik

Nice that the article has focused on practical solutions and cautionary advice on overloading the default group. Usually, nobody cares and puts more and more jobs to the default, that's true.

A must-read for Magento developers looking to optimize cron job configurations.

Collapse
 
vpodorozh profile image
Vladyslav Podorozhnyi πŸ‡ΊπŸ‡¦ 🌻

UPD:

  • I've added a note regarding adding sequences into module.xml over modules configs we are aiming to change. Thx @dlmbr for noticing!
  • Fixed type in corn definitions closing tag - thx @abramchukm for noticing!
Collapse
 
olvajow profile image
OlvaJowDay

I haven't been working on Magento 2 for long, but I'm comfortable with my choice and also with the fact that I contacted Amasty for services. By the way, these specialists also provide a wide selection of various extensions, for example, magento 2 shipping table rates, which allow you to create the best website for your clients, completely covering their needs.