mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-07 18:44:08 +00:00
The documents are now generated in a queue, using symfony messenger. This queue should be configured: ```yaml # app/config/messenger.yaml framework: messenger: # reset services after consuming messages # reset_on_message: true failure_transport: failed transports: # https://symfony.com/doc/current/messenger.html#transport-configuration async: '%env(MESSENGER_TRANSPORT_DSN)%' priority: dsn: '%env(MESSENGER_TRANSPORT_DSN)%' failed: 'doctrine://default?queue_name=failed' routing: # ... other messages 'Chill\DocGeneratorBundle\Service\Messenger\RequestGenerationMessage': priority ``` `StoredObject`s now have additionnal properties: * status (pending, failure, ready (by default) ), which explain if the document is generated; * a generationTrialCounter, which is incremented on each generation trial, which prevent each generation more than 5 times; The generator computation is moved from the `DocGenTemplateController` to a `Generator` (implementing `GeneratorInterface`. There are new methods to `Context` which allow to normalize/denormalize context data to/from a messenger's `Message`.
157 lines
5.7 KiB
PHP
157 lines
5.7 KiB
PHP
<?php
|
|
|
|
namespace Chill\DocGeneratorBundle\Service\Messenger;
|
|
|
|
use Chill\DocGeneratorBundle\Repository\DocGeneratorTemplateRepository;
|
|
use Chill\DocGeneratorBundle\Service\Generator\GeneratorException;
|
|
use Chill\DocStoreBundle\Entity\StoredObject;
|
|
use Chill\DocStoreBundle\Repository\StoredObjectRepository;
|
|
use Chill\MainBundle\Repository\UserRepositoryInterface;
|
|
use Doctrine\ORM\EntityManagerInterface;
|
|
use Psr\Log\LoggerInterface;
|
|
use Symfony\Bridge\Twig\Mime\TemplatedEmail;
|
|
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
|
use Symfony\Component\Mailer\MailerInterface;
|
|
use Symfony\Component\Messenger\Event\WorkerMessageFailedEvent;
|
|
use Symfony\Contracts\Translation\TranslatorInterface;
|
|
|
|
final class OnGenerationFails implements EventSubscriberInterface
|
|
{
|
|
private DocGeneratorTemplateRepository $docGeneratorTemplateRepository;
|
|
|
|
private EntityManagerInterface $entityManager;
|
|
|
|
private LoggerInterface $logger;
|
|
|
|
private MailerInterface $mailer;
|
|
|
|
private StoredObjectRepository $storedObjectRepository;
|
|
|
|
private TranslatorInterface $translator;
|
|
|
|
private UserRepositoryInterface $userRepository;
|
|
|
|
const LOG_PREFIX = '[docgen failed] ';
|
|
|
|
/**
|
|
* @param DocGeneratorTemplateRepository $docGeneratorTemplateRepository
|
|
* @param EntityManagerInterface $entityManager
|
|
* @param LoggerInterface $logger
|
|
* @param MailerInterface $mailer
|
|
* @param StoredObjectRepository $storedObjectRepository
|
|
* @param TranslatorInterface $translator
|
|
* @param UserRepositoryInterface $userRepository
|
|
*/
|
|
public function __construct(
|
|
DocGeneratorTemplateRepository $docGeneratorTemplateRepository,
|
|
EntityManagerInterface $entityManager,
|
|
LoggerInterface $logger,
|
|
MailerInterface $mailer,
|
|
StoredObjectRepository $storedObjectRepository,
|
|
TranslatorInterface $translator,
|
|
UserRepositoryInterface $userRepository
|
|
) {
|
|
$this->docGeneratorTemplateRepository = $docGeneratorTemplateRepository;
|
|
$this->entityManager = $entityManager;
|
|
$this->logger = $logger;
|
|
$this->mailer = $mailer;
|
|
$this->storedObjectRepository = $storedObjectRepository;
|
|
$this->translator = $translator;
|
|
$this->userRepository = $userRepository;
|
|
}
|
|
|
|
|
|
public static function getSubscribedEvents()
|
|
{
|
|
return [
|
|
WorkerMessageFailedEvent::class => 'onMessageFailed'
|
|
];
|
|
}
|
|
|
|
public function onMessageFailed(WorkerMessageFailedEvent $event): void
|
|
{
|
|
if ($event->willRetry()) {
|
|
return;
|
|
}
|
|
|
|
if (!$event->getEnvelope()->getMessage() instanceof RequestGenerationMessage) {
|
|
return;
|
|
}
|
|
|
|
/** @var \Chill\DocGeneratorBundle\Service\Messenger\RequestGenerationMessage $message */
|
|
$message = $event->getEnvelope()->getMessage();
|
|
|
|
$this->logger->error(self::LOG_PREFIX.'Docgen failed', [
|
|
'stored_object_id' => $message->getDestinationStoredObjectId(),
|
|
'entity_id' => $message->getEntityId(),
|
|
'template_id' => $message->getTemplateId(),
|
|
'creator_id' => $message->getCreatorId(),
|
|
'throwable_class' => get_class($event->getThrowable()),
|
|
]);
|
|
|
|
$this->markObjectAsFailed($message);
|
|
$this->warnCreator($message, $event);
|
|
}
|
|
|
|
private function markObjectAsFailed(RequestGenerationMessage $message): void
|
|
{
|
|
$object = $this->storedObjectRepository->find($message->getDestinationStoredObjectId());
|
|
|
|
if (null === $object) {
|
|
$this->logger->error(self::LOG_PREFIX.'Stored object not found', ['stored_object_id', $message->getDestinationStoredObjectId()]);
|
|
}
|
|
|
|
$object->setStatus(StoredObject::STATUS_FAILURE);
|
|
|
|
$this->entityManager->flush();
|
|
}
|
|
|
|
private function warnCreator(RequestGenerationMessage $message, WorkerMessageFailedEvent $event): void
|
|
{
|
|
if (null === $creatorId = $message->getCreatorId()) {
|
|
$this->logger->info(self::LOG_PREFIX.'creator id is null');
|
|
return;
|
|
}
|
|
|
|
if (null === $creator = $this->userRepository->find($creatorId)) {
|
|
$this->logger->error(self::LOG_PREFIX.'Creator not found with given id', ['creator_id', $creatorId]);
|
|
return;
|
|
}
|
|
|
|
if (null === $creator->getEmail() || '' === $creator->getEmail()) {
|
|
$this->logger->info(self::LOG_PREFIX.'Creator does not have any email', ['user' => $creator->getUsernameCanonical()]);
|
|
return;
|
|
}
|
|
|
|
// if the exception is not a GeneratorException, we try the previous one...
|
|
$throwable = $event->getThrowable();
|
|
if (!$throwable instanceof GeneratorException) {
|
|
$throwable = $throwable->getPrevious();
|
|
}
|
|
|
|
if ($throwable instanceof GeneratorException) {
|
|
$errors = $throwable->getErrors();
|
|
} else {
|
|
$errors = [$throwable->getTraceAsString()];
|
|
}
|
|
|
|
if (null === $template = $this->docGeneratorTemplateRepository->find($message->getTemplateId())) {
|
|
$this->logger->info(self::LOG_PREFIX.'Template not found', ['template_id' => $message->getTemplateId()]);
|
|
return;
|
|
}
|
|
|
|
$email = (new TemplatedEmail())
|
|
->to($creator->getEmail())
|
|
->subject($this->translator->trans('docgen.failure_email.The generation of a document failed'))
|
|
->textTemplate('@ChillDocGenerator/Email/on_generation_failed_email.txt.twig')
|
|
->context([
|
|
'errors' => $errors,
|
|
'template' => $template,
|
|
'creator' => $creator,
|
|
'stored_object_id' => $message->getDestinationStoredObjectId(),
|
|
]);
|
|
|
|
$this->mailer->send($email);
|
|
}
|
|
}
|