Simple CRON Jobs using Symfony's custom Commands - 266 reads

Unlock the power of Symfony's custom commands to streamline your CRON jobs effortlessly! In this post, discover how to harness Symfony's flexibility to create and manage automated jobs in the simplest way possible. From basic setup to advanced scheduling,

Let's dive into it!

Context: Today I was thinking of the simplest way to implement some sort of job to check my appointments on this web app once a day, and mark the approved ones that I forgot to manually close as "FULFILLED".

Upon further research in the Symfony Docs and other weird blogs, I found nothing except ambiguous interpretations of Doctrine's Messenger Interface. So I took it upon myself to find the simplest way to get a CRON Job up and running with Symfony (and basic hosting-side tools like CPanel), for lazy implementations such as this one:))

That being said, there are 3 main components we need:

  1. A custom Symfony command
  2. A custom Job
  3. A new CRON Job on our hosting


1.Custom Symfony command

Creating this is quite easy. In your src directory, create a new "Command" directory (if you don't already have one), and inside it add a new PHP file with a suggestive name. Take my structure as an example:

src/Command/RunJobCommand.php

I wanted to make this command generic, so it takes a job name parameter, just in case I want to implement other jobs in the future. Annotating commands is very similar to annotating routes, so you should find the code bellow easy to understand:

#[AsCommand(name: 'app:run-job', description: 'Runs a given job.', aliases: ['app:job:execute'])]

Let's start writing the class and it's attributes. The class must extend Command class for this to work:

class RunJobCommand extends Command
{
 protected static $defaultName = 'app:run-job'; // command name
 private FulfillOverdueBookings $fulfillOverdueBookings; // job class, check step 2
}

Our command class also needs to extend the configure and execute methods:

protected function configure(): void {
$this
  ->setDescription('Run a job.')
  ->setHelp('This command allows you to run a job...')
  ->addArgument('jobName', InputArgument::REQUIRED, 'The name of the job to run.'); // force command to take parameter as such: app:run-job MyJob
}


protected function execute(InputInterface $input, OutputInterface $output): int {
 $jobName = $input->getArgument('jobName'); // the mandatory parameter

 switch ($jobName) {
  case 'fulfillOverdueBookings':
   $output->writeln('Running the fulfillOverdueBookings job.');
   try {
    $this->fulfillOverdueBookings->execute(); // call to our Job execute method, check next step for more info
   } catch (\Exception $e) {
    $output->writeln('An error occurred: ' . $e->getMessage());
    return Command::FAILURE;
   }
   break;
  // add more cases here for other jobs
  default:
   $output->writeln('The job name is not valid.');
   return Command::FAILURE;
 }
 return Command::SUCCESS;
}

And boom! We have our command set up and ready to go! Let's now create our custom Job!


2.Custom Job

Similarly to creating a command, in your src directory, create a new "Job" directory (this is not a pre-defined directory in this case, so name it however you see fit), and inside it add a new PHP file with a suggestive Job name. Here is what I came up with:

src/Job/FulfillOverdueBookings.php

This class will be as basic as it gets, because we don't have to implement any interface or anything of this sort. Just apply any logic you need here:

class FulfillOverdueBookings
{
 // define attributes as needed
 public function execute(): void {
  // do whatever you need here...
 }
}


3.Defining CRON Jobs in CPanel

You can probably find resources all over the place on this subject, but for the sake of simplicity, just log into your CPanel account, search in the upper right bar for "Cron Jobs", and click it.

In the "Add New Cron Job" section, choose from "Common Settings" the frequency of the job. In my case, I want to check every day for the bookings from the previous day, so I will choose "Once Per Day", or just input (0 0 * * *) for custom settings.

For the "Command" input, use the "General example" given by CPanel to extract the absolute path to your user, and add your custom command at the end as such:

/usr/local/bin/php /var/home/my_user/my_app_dir/bin/console app:run-job fulfillOverdueBookings


And BOOM! Now this CRON will run the app:run-job fulfillOverdueBookings command once per day in your app!

There we have it! Your brand new custom Job working with Symfony, implemented in the simplest way possible!