Step 24: Running Crons

Running Crons

Comments marked as spam or rejected by the admin are kept in the database as the admin might want to inspect them for a little while. But they should probably be removed after some time. Keeping them around for a week after their creation is probably enough.

Create some utility methods in the comment repository to find rejected comments, count them, and delete them:

patch_file

Tip

For more complex queries, it is sometimes useful to have a look at the generated SQL statements (they can be found in the logs and in the profiler for Web requests).

7 days? We could have chosen another number, maybe 10 or 20. This number might evolve over time. We have decided to store it as a constant on the class, but we might have stored it as a parameter in the container, or we might have even defined it as an environment variable.

  • If the value is sensitive (passwords, API tokens, …), use the Symfony secret storage or a Vault;
  • If the value is dynamic and you should be able to change it without re-deploying, use an environment variable;
  • If the value can be different between environments, use a container parameter;
  • For everything else, store the value in code, like in a class constant.

Removing the old comments is the perfect task for a cron job. It should be done on a regular basis, and a little delay does not have any major impact.

Create a CLI command named by creating a src/Command/CommentCleanupCommand.php file:

src/Command/CommentCleanupCommand.php

  1. namespace App\Command;
  2. use App\Repository\CommentRepository;
  3. use Symfony\Component\Console\Command\Command;
  4. use Symfony\Component\Console\Input\InputInterface;
  5. use Symfony\Component\Console\Input\InputOption;
  6. use Symfony\Component\Console\Output\OutputInterface;
  7. use Symfony\Component\Console\Style\SymfonyStyle;
  8. class CommentCleanupCommand extends Command
  9. {
  10. private $commentRepository;
  11. public function __construct(CommentRepository $commentRepository)
  12. {
  13. $this->commentRepository = $commentRepository;
  14. parent::__construct();
  15. }
  16. protected function configure()
  17. {
  18. ->setDescription('Deletes rejected and spam comments from the database')
  19. ->addOption('dry-run', null, InputOption::VALUE_NONE, 'Dry run')
  20. ;
  21. }
  22. protected function execute(InputInterface $input, OutputInterface $output): int
  23. {
  24. $io = new SymfonyStyle($input, $output);
  25. if ($input->getOption('dry-run')) {
  26. $io->note('Dry mode enabled');
  27. $count = $this->commentRepository->countOldRejected();
  28. } else {
  29. $count = $this->commentRepository->deleteOldRejected();
  30. }
  31. $io->success(sprintf('Deleted "%d" old rejected/spam comments.', $count));
  32. return 0;
  33. }
  34. }

All application commands are registered alongside Symfony built-in ones and they are all accessible via symfony console. As the number of available commands can be large, you should namespace them. By convention, the application commands should be stored under the app namespace. Add any number of sub-namespaces by separating them by a colon (:).

A command gets the input (arguments and options passed to the command) and you can use the output to write to the console.

Clean up the database by running the command:

patch_file

  1. --- a/.symfony.cloud.yaml
  2. +++ b/.symfony.cloud.yaml
  3. @@ -52,6 +52,15 @@ hooks:
  4. (>&2 symfony-deploy)
  5. +crons:
  6. + comment_cleanup:
  7. + # Cleanup every night at 11.50 pm (UTC).
  8. + spec: '50 23 * * *'
  9. + cmd: |
  10. + if [ "$SYMFONY_BRANCH" = "master" ]; then
  11. + croncape symfony console app:comment:cleanup
  12. + fi
  13. +
  14. workers:
  15. messages:
  16. commands:

The crons section defines all cron jobs. Each cron runs according to a spec schedule.

The croncape utility monitors the execution of the command and sends an email to the addresses defined in the MAILTO environment variable if the command returns any exit code different than 0.

Configure the MAILTO environment variable:

You can force a cron to run on your local machine:

  1. $ symfony cron comment_cleanup

Note that crons are set up on all SymfonyCloud branches. If you don’t want to run some on non-production environments, check the environment variable:


This work, including the code samples, is licensed under a Creative Commons BY-NC-SA 4.0 license.