步骤 24: 运行 cron 定时任务

    被标记为垃圾信息的评论,以及被管理员拒绝的评论,它们仍会保留在数据库,因为管理员可能会在一段时间内对它们进行检查。在过了一阵后,很可能需要把它们清理掉。这样的评论从创建后保留一星期应该够了。

    在评论对应的 repository 类里新增一些工具方法,用来找到被拒绝的评论,清点这些评论的总数以及删除它们:

    patch_file

    小技巧

    对于更复杂的查询,有时候看一下生成的 SQL 语句会很有帮助(你能在日志和 web 请求分析器中找到这些语句)。

    7 天?我们本来也可以用另外一个数字,或许是 10 天或 20 天。这个数字可能会随着时间推移而改变。我们决定了把它存储为类里的一个常量,但我们也可以将它存储为容器里的一个参数,甚至可以把它定义为一个环境变量。

    • 如果这个值是敏感信息(密码,API 令牌等),就用 Symfony 的 机密存储 或保险箱机制;
    • 如果这个值是动态的,并且你需要 经重新部署就能去更新它,那么就使用 环境变量
    • 如果这个值可能依据环境而不同,那么就用 容器参数
    • 对于其它情况,就把这个值存储在代码中,比如在一个 类常量 中。

    用 cron 任务来删除旧评论非常合适。它应该定期执行,而且稍有耽误也不会有大的影响。

    通过新建 文件来创建一个名为 app:comment:cleanup 的新命令:

    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. protected static $defaultName = 'app:comment:cleanup';
    12. public function __construct(CommentRepository $commentRepository)
    13. {
    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. }

    应用程序的所有命令会和 Symfony 自带的命令注册在一起,它们都可以通过 symfony console 来执行。因为可用的命令数量很多,你应该用命名空间来管理它们。习惯上应用程序自己的命令会在 app 命名空间下。你可以用冒号(:)来增加任意数量的子命名空间。

    一个命令接收 输入 (传递给命令的参数和选项),你也可以把 输出 写到控制台上。

    通过执行这个命令来清理数据库:

    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:

    crons 的配置段定义了所有 cron 任务。每一个 cron 任务根据 spec 里的安排来执行。

    croncape 工具会监控命令的执行,如果一个命令返回了非 0 的退出码,该工具就会发送一封邮件到 MAILTO 环境变量定义的地址。

    设置 MAILTO 环境变量:

    在你的本地机器上,你能让一个 cron 任务强制执行:

    1. $ symfony cron comment_cleanup

    请注意 cron 任务在 SymfonyCloud 的所有分支上都设置了。如果在非生产环境中你不想执行某些任务,你可以检查 环境变量: