/** * If workflow message handler receives a collect-data message it forwards the message to this * method and uses the returned ProcessingMessage as response * * @param WorkflowMessage $workflowMessage * @return ProcessingMessage */ protected function handleCollectData(WorkflowMessage $workflowMessage) { if ($workflowMessage->payload()->getTypeClass() === 'Prooph\\ProcessingExample\\Type\\SourceUser') { $userData = (include __DIR__ . '/../../data/user-source-data.php'); if (!$userData) { return LogMessage::logErrorMsg("Could not read user data from examples/data/user-source-data.php. Please check the permissions", $workflowMessage); } $sourceUser = SourceUser::fromNativeValue($userData); return $workflowMessage->answerWith($sourceUser); } else { return LogMessage::logErrorMsg(sprintf('%s: Unknown type %s received', __CLASS__, $workflowMessage->payload()->getTypeClass()), $workflowMessage); } }
/** * If workflow message handler receives a process-data message it forwards the message to this * method and uses the returned ProcessingMessage as response * * @param WorkflowMessage $workflowMessage * @return ProcessingMessage */ protected function handleProcessData(WorkflowMessage $workflowMessage) { if (array_key_exists($workflowMessage->payload()->getTypeClass(), $this->getSupportedMessagesByTypeMap())) { $dataAsJsonString = json_encode($workflowMessage->payload()); $answer = $workflowMessage->answerWithDataProcessingCompleted(); try { \Zend\Stdlib\ErrorHandler::start(); if (!file_put_contents(__DIR__ . '/../../data/target-data.txt', $dataAsJsonString)) { \Zend\Stdlib\ErrorHandler::stop(true); } } catch (\Exception $ex) { $answer = \Prooph\Processing\Message\LogMessage::logException($ex, $workflowMessage); } return $answer; } else { return LogMessage::logErrorMsg(sprintf('%s: Unknown type %s received', __CLASS__, $workflowMessage->payload()->getTypeClass()), $workflowMessage); } }
public function provideMessages() { $localTaskListPosition = TaskListPosition::at(TaskListId::linkWith(NodeName::defaultName(), ProcessId::generate()), 1); $remoteTaskListPosition = TaskListPosition::at(TaskListId::linkWith(NodeName::fromString("remote-system"), ProcessId::generate()), 1); $wfMessageWithoutTaskListPosition = WorkflowMessage::collectDataOf(TestUser::prototype(), 'test-case', 'localhost'); $expectedDataWfMessageWithoutTaskListPosition = ['message_id' => $wfMessageWithoutTaskListPosition->uuid()->toString(), 'message_name' => $wfMessageWithoutTaskListPosition->messageName(), 'version' => $wfMessageWithoutTaskListPosition->version(), 'task_list_position' => null, 'process_id' => null, 'status' => MessageStatus::PENDING, 'failure_msg' => null]; $wfMessageWithTaskListPosition = WorkflowMessage::collectDataOf(TestUser::prototype(), 'test-case', 'localhost'); $wfMessageWithTaskListPosition->connectToProcessTask($localTaskListPosition); $expectedDataWfMessageWithTaskListPosition = ['message_id' => $wfMessageWithTaskListPosition->uuid()->toString(), 'message_name' => $wfMessageWithTaskListPosition->messageName(), 'version' => $wfMessageWithTaskListPosition->version(), 'task_list_position' => $wfMessageWithTaskListPosition->processTaskListPosition()->toString(), 'process_id' => $wfMessageWithTaskListPosition->processTaskListPosition()->taskListId()->processId()->toString(), 'status' => MessageStatus::PENDING, 'failure_msg' => null]; $logMessage = LogMessage::logDebugMsg("Log message", $wfMessageWithTaskListPosition); $expectedDataLogMessage = ['message_id' => $logMessage->uuid()->toString(), 'message_name' => $logMessage->messageName(), 'version' => 1, 'task_list_position' => $logMessage->processTaskListPosition()->toString(), 'process_id' => $logMessage->processTaskListPosition()->taskListId()->processId()->toString(), 'status' => MessageStatus::PENDING, 'failure_msg' => null]; $startSubProcess = StartSubProcess::at($localTaskListPosition, ["process_type" => "faked"], false, "remote-system"); $expectedDataStartSubProcess = ['message_id' => $startSubProcess->uuid()->toString(), 'message_name' => $startSubProcess->messageName(), 'version' => $startSubProcess->version(), 'task_list_position' => $startSubProcess->parentTaskListPosition()->toString(), 'process_id' => $startSubProcess->parentTaskListPosition()->taskListId()->processId()->toString(), 'status' => MessageStatus::PENDING, 'failure_msg' => null]; $wfMessageWithRemoteTaskListPosition = WorkflowMessage::collectDataOf(TestUser::prototype(), 'test-case', 'localhost'); $wfMessageWithRemoteTaskListPosition->connectToProcessTask($remoteTaskListPosition); $logMessageSubProcess = LogMessage::logErrorMsg("Faked error", $wfMessageWithRemoteTaskListPosition); $subProcessFinished = SubProcessFinished::record(NodeName::fromString("remote-system"), $remoteTaskListPosition->taskListId()->processId(), false, $logMessageSubProcess, $localTaskListPosition); $expectedDataSubProcessFinished = ['message_id' => $subProcessFinished->uuid()->toString(), 'message_name' => $subProcessFinished->messageName(), 'version' => $subProcessFinished->version(), 'task_list_position' => $logMessageSubProcess->processTaskListPosition()->toString(), 'process_id' => $logMessageSubProcess->processTaskListPosition()->taskListId()->processId()->toString(), 'status' => MessageStatus::PENDING, 'failure_msg' => null]; return [[$wfMessageWithoutTaskListPosition, $expectedDataWfMessageWithoutTaskListPosition], [$wfMessageWithoutTaskListPosition->toServiceBusMessage(), $expectedDataWfMessageWithoutTaskListPosition], [$wfMessageWithTaskListPosition, $expectedDataWfMessageWithTaskListPosition], [$wfMessageWithTaskListPosition->toServiceBusMessage(), $expectedDataWfMessageWithTaskListPosition], [$logMessage, $expectedDataLogMessage], [$logMessage->toServiceBusMessage(), $expectedDataLogMessage], [$startSubProcess, $expectedDataStartSubProcess], [$startSubProcess->toServiceBusMessage(), $expectedDataStartSubProcess], [$subProcessFinished, $expectedDataSubProcessFinished], [$subProcessFinished->toServiceBusMessage(), $expectedDataSubProcessFinished]]; }
/** * @param TaskListPosition $taskListPosition * @param WorkflowMessage|LogMessage $lastAnswer * @throws \RuntimeException If process cannot be found * @throws \Exception If error occurs during processing */ private function continueProcessAt(TaskListPosition $taskListPosition, $lastAnswer) { $process = $this->processRepository->get($taskListPosition->taskListId()->processId()); if (is_null($process)) { throw new \RuntimeException(sprintf("Last received message %s (%s) contains unknown processId. A process with id %s cannot be found!", $lastAnswer->getMessageName(), $lastAnswer->uuid()->toString(), $taskListPosition->taskListId()->processId()->toString())); } $this->beginTransaction(); try { $process->receiveMessage($lastAnswer, $this->workflowEngine); $this->commitTransaction(); } catch (\Exception $ex) { $this->rollbackTransaction(); throw $ex; } if ($process->isFinished()) { $this->processorEventQueue->enqueue($this->events()->getNewActionEvent('process_did_finish', $this, ['process_id' => $process->processId()->toString(), 'finished_at' => $lastAnswer->createdAt()->format(\DateTime::ISO8601), 'succeed' => $process->isSuccessfulDone()])); } if ($process->isSubProcess() && $process->isFinished()) { if ($process->isSuccessfulDone()) { $this->informParentProcessAboutSubProcess($process, true, $lastAnswer); } else { if (!$lastAnswer instanceof LogMessage) { $lastAnswer = LogMessage::logException(new \RuntimeException("Sub process failed but last message was not a LogMessage"), $process->parentTaskListPosition()); } if (!$lastAnswer->isError()) { $lastAnswer = LogMessage::logErrorMsg($lastAnswer->technicalMsg(), $lastAnswer); } $this->informParentProcessAboutSubProcess($process, false, $lastAnswer); } } }
/** * @test */ public function it_marks_task_of_parent_process_as_failed_when_sub_process_is_finished_with_error() { $this->setUpOtherMachine(); $wfMessage = $this->getUserDataCollectedTestMessage(); /** * Change type to scenario 2 type, so that @see \Prooph\ProcessingTest\TestCase::getTestProcessFactory * set up the right process */ $wfMessage->changeProcessingType('Prooph\\ProcessingTest\\Mock\\UserDictionaryS2'); $this->getTestWorkflowProcessor()->receiveMessage($wfMessage); $receivedMessage = $this->otherMachineWorkflowMessageHandler->lastWorkflowMessage(); $this->assertNotNull($receivedMessage); $error = LogMessage::logErrorMsg("Simulated error", $receivedMessage); $this->getOtherMachineWorkflowProcessor()->receiveMessage($error); $this->assertNotNull($this->lastPostCommitEvent); $expectedEventNamesLocalhost = ['Prooph\\Processing\\Processor\\Event\\ProcessWasSetUp', 'Prooph\\Processing\\Processor\\Task\\Event\\TaskEntryMarkedAsRunning', 'Prooph\\Processing\\Processor\\Task\\Event\\LogMessageReceived', 'Prooph\\Processing\\Processor\\Task\\Event\\TaskEntryMarkedAsFailed']; $expectedEventNamesOtherMachine = ['Prooph\\Processing\\Processor\\Event\\ProcessWasSetUp', 'Prooph\\Processing\\Processor\\Task\\Event\\TaskEntryMarkedAsRunning', 'Prooph\\Processing\\Processor\\Task\\Event\\LogMessageReceived', 'Prooph\\Processing\\Processor\\Task\\Event\\TaskEntryMarkedAsFailed']; $this->assertEquals($expectedEventNamesLocalhost, $this->eventNameLog); $this->assertEquals($expectedEventNamesOtherMachine, $this->otherMachineEventNameLog); }
/** * Start or continue the process with the help of given WorkflowEngine and optionally with given WorkflowMessage * * @param WorkflowEngine $workflowEngine * @param WorkflowMessage $workflowMessage * @throws \RuntimeException * @throws \BadMethodCallException * @return void */ public function perform(WorkflowEngine $workflowEngine, WorkflowMessage $workflowMessage = null) { $taskListEntry = $this->taskList->getNextNotStartedTaskListEntry(); if (is_null($taskListEntry)) { throw new \RuntimeException('ForEachProcess::perform was called but there are no tasks configured!'); } if (is_null($workflowMessage)) { $this->recordThat(TaskEntryMarkedAsRunning::at($taskListEntry->taskListPosition())); $this->receiveMessage(LogMessage::logNoMessageReceivedFor($taskListEntry->task(), $taskListEntry->taskListPosition()), $workflowEngine); return; } $workflowMessage = $workflowMessage->reconnectToProcessTask($taskListEntry->taskListPosition()); if (count($this->taskList->getAllTaskListEntries()) > 1) { $this->recordThat(TaskEntryMarkedAsRunning::at($taskListEntry->taskListPosition())); $this->receiveMessage(LogMessage::logErrorMsg('The ForEachProcess can only handle a single RunSubProcess task but there are more tasks configured', $workflowMessage), $workflowEngine); return; } if (!$taskListEntry->task() instanceof RunSubProcess) { $this->recordThat(TaskEntryMarkedAsRunning::at($taskListEntry->taskListPosition())); $this->receiveMessage(LogMessage::logErrorMsg(sprintf('The ForEachProcess can only handle a RunSubProcess task but there is a %s task configured', get_class($taskListEntry->task())), $workflowMessage), $workflowEngine); return; } if (!MessageNameUtils::isProcessingEvent($workflowMessage->messageName())) { $this->recordThat(TaskEntryMarkedAsRunning::at($taskListEntry->taskListPosition())); $this->receiveMessage(LogMessage::logWrongMessageReceivedFor($taskListEntry->task(), $taskListEntry->taskListPosition(), $workflowMessage), $workflowEngine); return; } $collection = $workflowMessage->payload()->toType(); if (!$collection instanceof CollectionType) { $this->receiveMessage(LogMessage::logErrorMsg(sprintf('The ForEachProcess requires a Prooph\\ProcessingType\\CollectionType as payload of the incoming message, but it is a %s type given', $workflowMessage->payload()->getTypeClass()), $workflowMessage), $workflowEngine); return; } $this->startSubProcessForEachItem($collection, $workflowEngine); }
/** * @param string $msg * @param WorkflowMessage $workflowMessage * @param WorkflowEngine $workflowEngine */ protected function logErrorMsg($msg, WorkflowMessage $workflowMessage, WorkflowEngine $workflowEngine) { $this->receiveMessage(LogMessage::logErrorMsg($msg, $workflowMessage), $workflowEngine); }