From 5287824dbefda465479bdcf2df14b688b86cd050 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Wed, 25 Sep 2024 11:58:41 +0200 Subject: [PATCH] Add async handling for signature state changes Introduce MessageBus to handle post-signature operations asynchronously. This ensures that further steps are executed through dispatched messages, improving system scalability and performance. Implement new handlers and messages for the workflow state transitions. --- .../SignatureStepStateChangerTest.php | 13 +++++- .../PostSignatureStateChangeHandler.php | 41 +++++++++++++++++++ .../PostSignatureStateChangeMessage.php | 22 ++++++++++ .../Workflow/SignatureStepStateChanger.php | 14 ++++++- 4 files changed, 86 insertions(+), 4 deletions(-) create mode 100644 src/Bundle/ChillMainBundle/Workflow/Messenger/PostSignatureStateChangeHandler.php create mode 100644 src/Bundle/ChillMainBundle/Workflow/Messenger/PostSignatureStateChangeMessage.php diff --git a/src/Bundle/ChillMainBundle/Tests/Workflow/SignatureStepStateChangerTest.php b/src/Bundle/ChillMainBundle/Tests/Workflow/SignatureStepStateChangerTest.php index 16579cbb5..fa3cd5c2d 100644 --- a/src/Bundle/ChillMainBundle/Tests/Workflow/SignatureStepStateChangerTest.php +++ b/src/Bundle/ChillMainBundle/Tests/Workflow/SignatureStepStateChangerTest.php @@ -21,6 +21,7 @@ use Chill\PersonBundle\Entity\Person; use PHPUnit\Framework\TestCase; use Psr\Log\NullLogger; use Symfony\Component\Clock\MockClock; +use Symfony\Component\Messenger\MessageBus; use Symfony\Component\Workflow\DefinitionBuilder; use Symfony\Component\Workflow\Metadata\InMemoryMetadataStore; use Symfony\Component\Workflow\Registry; @@ -44,7 +45,9 @@ class SignatureStepStateChangerTest extends TestCase $workflow = $registry->get($entityWorkflow, 'dummy'); $clock = new MockClock(); $user = new User(); - $changer = new SignatureStepStateChanger($registry, $clock, new NullLogger()); + + $messengerBus = new MessageBus([]); + $changer = new SignatureStepStateChanger($registry, $clock, new NullLogger(), $messengerBus); // move it to signature $dto = new WorkflowTransitionContextDTO($entityWorkflow); @@ -61,6 +64,8 @@ class SignatureStepStateChangerTest extends TestCase // we mark the first signature as signed $changer->markSignatureAsSigned($signatures[0], 1); + // the next step should be done by handling an async message + $changer->onPostMark($signatures[0]); self::assertEquals('signature', $entityWorkflow->getStep(), 'there should have any change in the entity workflow step'); self::assertEquals(EntityWorkflowSignatureStateEnum::SIGNED, $signatures[0]->getState()); @@ -70,6 +75,8 @@ class SignatureStepStateChangerTest extends TestCase // we mark the second signature as signed $changer->markSignatureAsSigned($signatures[1], 2); + // the next step should be done by handling an async message + $changer->onPostMark($signatures[1]); self::assertEquals(EntityWorkflowSignatureStateEnum::SIGNED, $signatures[1]->getState()); self::assertEquals('post-signature', $entityWorkflow->getStep(), 'the entity workflow step should be post-signature'); self::assertContains($user, $entityWorkflow->getCurrentStep()->getAllDestUser()); @@ -85,7 +92,7 @@ class SignatureStepStateChangerTest extends TestCase $workflow = $registry->get($entityWorkflow, 'dummy'); $clock = new MockClock(); $user = new User(); - $changer = new SignatureStepStateChanger($registry, $clock, new NullLogger()); + $changer = new SignatureStepStateChanger($registry, $clock, new NullLogger(), new MessageBus([])); // move it to signature $dto = new WorkflowTransitionContextDTO($entityWorkflow); @@ -102,6 +109,8 @@ class SignatureStepStateChangerTest extends TestCase // we mark the first signature as signed $changer->markSignatureAsSigned($signatures[0], 1); + // the next step should be done by handling an async message + $changer->onPostMark($signatures[0]); self::assertEquals('signature-without-metadata', $entityWorkflow->getStep(), 'there should have any change in the entity workflow step'); self::assertEquals(EntityWorkflowSignatureStateEnum::SIGNED, $signatures[0]->getState()); diff --git a/src/Bundle/ChillMainBundle/Workflow/Messenger/PostSignatureStateChangeHandler.php b/src/Bundle/ChillMainBundle/Workflow/Messenger/PostSignatureStateChangeHandler.php new file mode 100644 index 000000000..1a0d7bc5d --- /dev/null +++ b/src/Bundle/ChillMainBundle/Workflow/Messenger/PostSignatureStateChangeHandler.php @@ -0,0 +1,41 @@ +entityWorkflowStepSignatureRepository->find($message->signatureId); + + if (null === $signature) { + throw new UnrecoverableMessageHandlingException('signature not found'); + } + + $this->signatureStepStateChanger->onPostMark($signature); + + $this->entityManager->flush(); + $this->entityManager->clear(); + } +} diff --git a/src/Bundle/ChillMainBundle/Workflow/Messenger/PostSignatureStateChangeMessage.php b/src/Bundle/ChillMainBundle/Workflow/Messenger/PostSignatureStateChangeMessage.php new file mode 100644 index 000000000..44db0c500 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Workflow/Messenger/PostSignatureStateChangeMessage.php @@ -0,0 +1,22 @@ +setZoneSignatureIndex($atIndex) ->setStateDate($this->clock->now()); $this->logger->info(self::LOG_PREFIX.'Mark signature entity as signed', ['signatureId' => $signature->getId(), 'index' => (string) $atIndex]); - $this->onPostMark($signature); + $this->messageBus->dispatch(new PostSignatureStateChangeMessage((int) $signature->getId())); } public function markSignatureAsCanceled(EntityWorkflowStepSignature $signature): void @@ -45,6 +48,7 @@ class SignatureStepStateChanger ->setState(EntityWorkflowSignatureStateEnum::CANCELED) ->setStateDate($this->clock->now()); $this->logger->info(self::LOG_PREFIX.'Mark signature entity as canceled', ['signatureId' => $signature->getId()]); + $this->messageBus->dispatch(new PostSignatureStateChangeMessage((int) $signature->getId())); } public function markSignatureAsRejected(EntityWorkflowStepSignature $signature): void @@ -53,9 +57,15 @@ class SignatureStepStateChanger ->setState(EntityWorkflowSignatureStateEnum::REJECTED) ->setStateDate($this->clock->now()); $this->logger->info(self::LOG_PREFIX.'Mark signature entity as rejected', ['signatureId' => $signature->getId()]); + $this->messageBus->dispatch(new PostSignatureStateChangeMessage((int) $signature->getId())); } - private function onPostMark(EntityWorkflowStepSignature $signature): void + /** + * Executed after a signature has a new state. + * + * This should be executed only by a system user (without any user registered) + */ + public function onPostMark(EntityWorkflowStepSignature $signature): void { if (!EntityWorkflowStepSignature::isAllSignatureNotPendingForStep($signature->getStep())) { $this->logger->info(self::LOG_PREFIX.'This is not the last signature, skipping transition to another place', ['signatureId' => $signature->getId()]);