Scheduling Execution in PHP

We often need to schedule execution of given business functionality. In this article we will check different types of schedules in PHP.

Scheduling Execution in PHP

We often need to schedule the execution of given business functionality in our applications.
The timing depends on what we want to achieve. It may be monthly executed invoices or notifications sent after the user was registered on the website.
And in this article, we will deep into different ways of scheduling execution in PHP.

This article assumes basic knowledge about Commands and Events.

Scheduled Batch Job

The most common approach is scheduled batch jobs.
This is a process that rises at a specific hour, in most of the cases executes big database Query, fetches a large portion of data and execute related actions.

In PHP world Scheduled Batch Jobs are mostly implemented by Cron Jobs, that executes process at given time.

Batches are pretty straightforward in implementation, access to database, iterate and execute.
What we could achieve by that?

  • We could fetch all users that have registered within the last 15 minutes, to send them a welcome notification.
  • We could fetch all the orders to recalculate company earning statistics.
  • For a particular user we may have an agreement to invoice him at a given date, so we would look for overdue dates to generate it

Scheduled Jobs Implementation

Having a system cron job often creates problems with tracking if something went wrong and requires running non-PHP process.
If this is problematic for you, Ecotone brings Scheduled Jobs into PHP.

Scheduled Method

EndpointId in #[Scheduled] defines the name, that will be used to execute the process. #[Poller] defines how this method should be executed.

This method will be scheduled for execution every 10 seconds.
The process can be now run:

# Symfony 
bin/console ecotone:run notificationSender -vvv
# Laravel 
artisan ecotone:run notificationSender -vvv
# Lite 
$messagingSystem->run("notificationSender");

Scheduled Handler

You may also schedule execution of given Command Handler.

The first parameter of #[Scheduled] indicated routing to Command Handler.
In this case, we have set up Cron to execute every minute and call our Command Handler.

Problems with Scheduled Batch Jobs

There may be moments in time when Scheduled Batch Jobs will become problematic.

  • Batch Jobs often generate a huge load on database, which affects end-users of the system.
  • What if the batch job will fail at midnight?
    If we can catch it and notify, then users of the system are in luck, however, developers may have another sleepless night.
    This becomes even more problematic if our script breaks in the middle of processing. As we need to recover from that and run the job only for part of the data, that was not yet processed.
  • And what if we want to perform actions during the day?
    We either need to increase the system resources or agree that it may affect end users during that time.

So there must be a better approach, right?

Messaging

Messaging architecture provides us with a solid and stable platform to handle such problems.
It helps us in building applications that can scale and perform well on high loads.

So what is Message?
A message is a letter that can inform about a recent event that happened in the system or command an action that the system should perform.

With Messaging we are dealing with one message (a record) at a time and to keep the system stable, we can queue messages up and deal with them when we are ready.
This solves the problem of being overloaded and handling many records at a time. As we can just queue messages up and work on them one by one.

Messaging provides more stability to the system as, if we fail we fail at specific Message, we can retry this message or put it for review and continue with processing other ones.

Static Message Schedules

Suppose that we want to send a notification to newly registered user 5 minutes after registration.

After registration, we are publishing event UserWasRegistered.
Now we can handle this Event asynchronously and delay the execution.

#[Delayed] describes in milliseconds how long we want to delay the execution.

Ecotone delivers copy of a message to each Event Handler. Thanks to that you may delay one Handler yet execute other one instantly

Dynamic Message Schedules

In case we would like to dynamically decide, when a given process should be executed, we can define it when sending a message.

Suppose the user made an order and if he does a quick product shipping, we want to delay it for 3 days or otherwise 7 days.

And our Command Handler

We are using asynchronous to have storage for the message we send.
We may for example back it by RabbitMQ or DBAL (Database).

Periodic Message Schedules

We may also want to do recurring actions, like invoicing. To perform given execution after given periods of time.

Let’s implement invoicing for a user.
After the user was registered, we will register the first attempt to generate the invoice.
When the invoice was generated, we will register another attempt with delay.

We are joining a new user to the flow after he registers.
In case the user would be blocked, then generateInvoice we could just do a return without publishing the event and the flow for a given user would simply end.
This will create a message flow, where we will keep generating the invoices for a given user at a time, till the moment when we will decide to stop it.

If you put #[Asynchronous] attribute on top of the class, it will apply to all the Handlers.

Summary

Ecotone brings a true Messaging Platform to PHP. It provides easy-to-follow tools to glue things together, in a solid and stable way.
Messaging is a powerful concept and once developers get used to that, it can save a lot of sleepless nights, especially in business-critical components.

You may read more about Ecotone here.
If you want to see the implementation of the following article using Ecotone Lite go here.