Skip to content
  • About
    • What is Symfony?
    • Community
    • News
    • Contributing
    • Support
  • Documentation
    • Symfony Docs
    • Symfony Book
    • Screencasts
    • Symfony Bundles
    • Symfony Cloud
    • Training
  • Services
    • Platform.sh for Symfony Best platform to deploy Symfony apps
    • SymfonyInsight Automatic quality checks for your apps
    • Symfony Certification Prove your knowledge and boost your career
    • SensioLabs Professional services to help you with Symfony
    • Blackfire Profile and monitor performance of your apps
  • Other
  • Blog
  • Download
sponsored by
  1. Home
  2. Documentation
  3. Symfony: The Fast Track
  4. Russian
  5. Выполнение заданий cron

Выполнение заданий cron

Задания cron полезны для задач администрирования. В отличие от воркеров, они запускаются на короткое время по расписанию.

Очистка ненужных комментариев

Комментарии, помеченные как спам или отклонённые администратором, хранятся в базе, чтобы администратор мог просмотреть их позже. Но они, вероятно, в любом случае должны быть удалены через определённое время. Думаю, что хранить такие комментарии в течение недели после создания будет достаточно.

Добавьте несколько вспомогательных методов в репозиторий комментариев для поиска, подсчёта и удаления отклонённых комментариев:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
--- a/src/Repository/CommentRepository.php
+++ b/src/Repository/CommentRepository.php
@@ -6,6 +6,7 @@ use App\Entity\Comment;
 use App\Entity\Conference;
 use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
 use Doctrine\Persistence\ManagerRegistry;
+use Doctrine\ORM\QueryBuilder;
 use Doctrine\ORM\Tools\Pagination\Paginator;

 /**
@@ -16,6 +17,8 @@ use Doctrine\ORM\Tools\Pagination\Paginator;
  */
 class CommentRepository extends ServiceEntityRepository
 {
+    private const DAYS_BEFORE_REJECTED_REMOVAL = 7;
+
     public const PAGINATOR_PER_PAGE = 2;

     public function __construct(ManagerRegistry $registry)
@@ -23,6 +26,29 @@ class CommentRepository extends ServiceEntityRepository
         parent::__construct($registry, Comment::class);
     }

+    public function countOldRejected(): int
+    {
+        return $this->getOldRejectedQueryBuilder()->select('COUNT(c.id)')->getQuery()->getSingleScalarResult();
+    }
+
+    public function deleteOldRejected(): int
+    {
+        return $this->getOldRejectedQueryBuilder()->delete()->getQuery()->execute();
+    }
+
+    private function getOldRejectedQueryBuilder(): QueryBuilder
+    {
+        return $this->createQueryBuilder('c')
+            ->andWhere('c.state = :state_rejected or c.state = :state_spam')
+            ->andWhere('c.createdAt < :date')
+            ->setParameters([
+                'state_rejected' => 'rejected',
+                'state_spam' => 'spam',
+                'date' => new \DateTimeImmutable(-self::DAYS_BEFORE_REJECTED_REMOVAL.' days'),
+            ])
+        ;
+    }
+
     public function getCommentPaginator(Conference $conference, int $offset): Paginator
     {
         $query = $this->createQueryBuilder('c')

Tip

Для более сложных запросов иногда полезно посмотреть сгенерированные SQL-запросы (которые можно найти в логах и в профилировщике веб-запросов).

Использование констант класса, параметров контейнера и переменных среды окружения

Почему именно 7 дней? Мы могли бы выбрать другое число, может быть 10 или 20. Это число потом может поменяться. Поэтому лучше всего хранить такие данные в константе класса, что мы и сделали, хотя это значение можно было поместить в параметр контейнера или даже определить соответствующую переменную окружения.

Несколько основных правил, по которым можно определить, какую абстракцию использовать:

  • Если значение является конфиденциальной информацией (пароли, токены API и т.д.), используйте секретное хранилище Symfony или Vault;
  • Если значение динамическое, которое должно изменяться без повторного развёртывания, используйте переменные окружения;
  • Если значение может различаться в разных окружениях, используйте параметры контейнера;
  • Во всех остальных случаях храните значение в коде, например, в константах класса.

Создание CLI-команды

Удаление старых комментариев — идеальное задание для cron. Оно должно выполняться регулярно и небольшие задержки в выполнении не играют существенной роли.

Создайте CLI-команду с названием app:comment:cleanup в файле src/Command/CommentCleanupCommand.php:

src/Command/CommentCleanupCommand.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
namespace App\Command;

use App\Repository\CommentRepository;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;

class CommentCleanupCommand extends Command
{
    private $commentRepository;

    protected static $defaultName = 'app:comment:cleanup';

    public function __construct(CommentRepository $commentRepository)
    {
        $this->commentRepository = $commentRepository;

        parent::__construct();
    }

    protected function configure()
    {
        $this
            ->setDescription('Deletes rejected and spam comments from the database')
            ->addOption('dry-run', null, InputOption::VALUE_NONE, 'Dry run')
        ;
    }

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $io = new SymfonyStyle($input, $output);

        if ($input->getOption('dry-run')) {
            $io->note('Dry mode enabled');

            $count = $this->commentRepository->countOldRejected();
        } else {
            $count = $this->commentRepository->deleteOldRejected();
        }

        $io->success(sprintf('Deleted "%d" old rejected/spam comments.', $count));

        return 0;
    }
}

Все команды приложения регистрируются вместе со встроенными командами Symfony, и все они доступны через symfony console. Поскольку количество доступных команд может быть большим, необходимо группировать их по пространствам имён. По соглашению команды приложения должны храниться в пространстве app. Можно добавлять любое количество подпространств, разделяя их двоеточием (:).

Команда принимает input (аргументы и параметры, переданные команде), а также output, который вы можете использовать для вывода данных в консоль.

Очистите базу данных, выполнив команду:

1
$ symfony console app:comment:cleanup

Настройка cron в Platform.sh

Одним из удобств Platform.sh является то, что большая часть конфигурации хранится в одном файле: .platform.app.yaml. Веб-контейнер, воркеры и cron-задания для простоты администрирования описаны в одном месте:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
--- a/.platform.app.yaml
+++ b/.platform.app.yaml
@@ -60,6 +60,14 @@ crons:
         spec: '50 23 * * *'
         cmd: if [ "$PLATFORM_BRANCH" = "main" ]; then croncape php-security-checker; fi

+    comment_cleanup:
+        # Cleanup every night at 11.50 pm (UTC).
+        spec: '50 23 * * *'
+        cmd: |
+            if [ "$PLATFORM_BRANCH" = "master" ]; then
+                croncape symfony console app:comment:cleanup
+            fi
+
 workers:
     messenger:
         commands:

Раздел crons описывает все задания cron. Каждое задание выполняется в соответствии с расписанием, указанным в свойстве spec.

Утилита croncape следит за выполнением задания и посылает электронное письмо на адреса, указанные в переменной окружения MAILTO, если команда возвращает код завершения, отличный от 0.

Настройте переменную окружения MAILTO:

1
$ symfony cloud:variable:create --sensitive=1 --level=project -y --name=env:MAILTO --value=ops@example.com

Обратите внимание, что задания для cron настроены для всех веток Platform.sh. Если вы не хотите запускать какие-то задания вне продакшена, проверьте переменную окружения $PLATFORM_BRANCH:

1
2
3
if [ "$PLATFORM_BRANCH" = "master" ]; then
    croncape symfony app:invoices:send
fi

Двигаемся дальше

  • Синтаксис cron/crontab;
  • Репозиторий Croncape;
  • Команды Symfony Console;
  • Шпаргалка по Symfony Console.
Previous page Изменение размера изображений
Next page Уведомление различными способами
This work, including the code samples, is licensed under a Creative Commons BY-NC-SA 4.0 license.
TOC
    Version

    Symfony 5.4 is backed by

    Symfony Code Performance Profiling

    Symfony Code Performance Profiling

    Make sure your project is risk free

    Make sure your project is risk free

    Version:
    Locale:
    ebook

    This book is backed by:

    see all backers

    Symfony footer

    Avatar of Christian Schmidt, a Symfony contributor

    Thanks Christian Schmidt for being a Symfony contributor

    6 commits • 558 lines changed

    View all contributors that help us make Symfony

    Become a Symfony contributor

    Be an active part of the community and contribute ideas, code and bug fixes. Both experts and newcomers are welcome.

    Learn how to contribute

    Symfony™ is a trademark of Symfony SAS. All rights reserved.

    • What is Symfony?

      • What is Symfony?
      • Symfony at a Glance
      • Symfony Components
      • Symfony Releases
      • Security Policy
      • Logo & Screenshots
      • Trademark & Licenses
      • symfony1 Legacy
    • Learn Symfony

      • Symfony Docs
      • Symfony Book
      • Reference
      • Bundles
      • Best Practices
      • Training
      • eLearning Platform
      • Certification
    • Screencasts

      • Learn Symfony
      • Learn PHP
      • Learn JavaScript
      • Learn Drupal
      • Learn RESTful APIs
    • Community

      • Symfony Community
      • SymfonyConnect
      • Events & Meetups
      • Projects using Symfony
      • Contributors
      • Symfony Jobs
      • Backers
      • Code of Conduct
      • Downloads Stats
      • Support
    • Blog

      • All Blog Posts
      • A Week of Symfony
      • Case Studies
      • Cloud
      • Community
      • Conferences
      • Diversity
      • Living on the edge
      • Releases
      • Security Advisories
      • Symfony Insight
      • Twig
      • SensioLabs Blog
    • Services

      • SensioLabs services
      • Train developers
      • Manage your project quality
      • Improve your project performance
      • Host Symfony projects

      Powered by

    Follow Symfony