/**
  * @param WorkflowMessage $workflowMessage
  * @return void
  */
 public function handleWorkflowMessage(WorkflowMessage $workflowMessage)
 {
     if (!MessageNameUtils::isProcessingCommand($workflowMessage->messageName())) {
         $this->workflowEngine->dispatch(LogMessage::logUnsupportedMessageReceived($workflowMessage));
     }
     try {
         if ($workflowMessage->messageType() === MessageNameUtils::COLLECT_DATA) {
             $processingMessage = $this->handleCollectData($workflowMessage);
             if (!$processingMessage instanceof ProcessingMessage) {
                 throw new \RuntimeException(sprintf("%s::handleCollectData method returned %s instead of a ProcessingMessage", get_called_class(), is_object($processingMessage) ? get_class($processingMessage) : gettype($processingMessage)));
             }
         } else {
             if ($workflowMessage->messageType() === MessageNameUtils::PROCESS_DATA) {
                 $processingMessage = $this->handleProcessData($workflowMessage);
                 if (!$processingMessage instanceof ProcessingMessage) {
                     throw new \RuntimeException(sprintf("%s::handleProcessData method returned %s instead of a ProcessingMessage", get_called_class(), is_object($processingMessage) ? get_class($processingMessage) : gettype($processingMessage)));
                 }
             } else {
                 $this->workflowEngine->dispatch(LogMessage::logUnsupportedMessageReceived($workflowMessage));
                 return;
             }
         }
         $this->workflowEngine->dispatch($processingMessage);
         return;
     } catch (\Exception $ex) {
         $this->workflowEngine->dispatch(LogMessage::logException($ex, $workflowMessage));
         return;
     }
 }
示例#2
0
 /**
  * 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);
     }
 }
 /**
  * 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)
 {
     try {
         return $this->processData($workflowMessage);
     } catch (\Exception $ex) {
         ErrorHandler::stop();
         return LogMessage::logException($ex, $workflowMessage);
     }
 }
示例#4
0
 /**
  * @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);
         }
     }
 }
示例#5
0
/**
 * The workflow engine provides access to the communication layer of the processing system.
 * Communication is based on ProophServiceBus. We use the idea of CQRS to decouple the
 * workflow processor from workflow message handlers which are responsible for processing
 * single tasks. A workflow message handler is normally the glue component which connects
 * Prooph\Processing with an external system. It receives commands from the processor like collect data or
 * process data and send events back to tell the processor what's happened.
 *
 * Each target (external system) gets a command bus and an event bus assigned. These are the communication
 * channels between the processor and the target.
 * You can use the full power of ProophServiceBus so a channel can be a local bus, a link to a messaging infrastructure,
 * a link to a worker queue, or a http remote interface.
 *
 * @return \Prooph\Processing\Processor\RegistryWorkflowEngine
 */
function _set_up_workflow_engine()
{
    $commandBus = new \Prooph\ServiceBus\CommandBus();
    $eventBus = new \Prooph\ServiceBus\EventBus();
    $commandRouter = new \Prooph\ServiceBus\Router\CommandRouter();
    //For our scenario it is enough to use a closure as workflow message handler
    //In a production system this should be a class loadable by Zend\ServiceManager
    //See the more complex scenarios to get an idea how such a set up can be look like.
    $commandRouter->route(\Prooph\Processing\Message\MessageNameUtils::getProcessDataCommandName('Prooph\\ProcessingExample\\Type\\SourceUser'))->to(function (\Prooph\Processing\Message\WorkflowMessage $message) use($eventBus) {
        $dataAsJsonString = json_encode($message->payload());
        $answer = $message->answerWithDataProcessingCompleted();
        try {
            \Zend\Stdlib\ErrorHandler::start();
            if (!file_put_contents('data/target-data.txt', $dataAsJsonString)) {
                \Zend\Stdlib\ErrorHandler::stop(true);
            }
        } catch (\Exception $ex) {
            $answer = \Prooph\Processing\Message\LogMessage::logException($ex, $message);
        }
        $eventBus->dispatch($answer);
    });
    $commandBus->utilize($commandRouter);
    $commandBus->utilize(new \Prooph\ServiceBus\InvokeStrategy\CallbackStrategy());
    $workflowEngine = new \Prooph\Processing\Processor\RegistryWorkflowEngine();
    $workflowEngine->registerCommandBus($commandBus, ['target-file-writer']);
    $workflowEngine->registerEventBus($eventBus, [\Prooph\Processing\Processor\Definition::SERVICE_WORKFLOW_PROCESSOR]);
    return $workflowEngine;
}
示例#6
0
 /**
  * @param ManipulatePayload $task
  * @param TaskListPosition $taskListPosition
  * @param WorkflowEngine $workflowEngine
  * @param WorkflowMessage $previousMessage
  */
 protected function performManipulatePayload(ManipulatePayload $task, TaskListPosition $taskListPosition, WorkflowEngine $workflowEngine, WorkflowMessage $previousMessage)
 {
     if (!MessageNameUtils::isProcessingEvent($previousMessage->messageName())) {
         $this->receiveMessage(LogMessage::logWrongMessageReceivedFor($task, $taskListPosition, $previousMessage), $workflowEngine);
         return;
     }
     $payload = $previousMessage->payload();
     try {
         $task->performManipulationOn($payload);
     } catch (\Exception $ex) {
         $this->receiveMessage(LogMessage::logException($ex, $taskListPosition), $workflowEngine);
         return;
     }
     $newEvent = $previousMessage->prepareDataProcessing($taskListPosition, $this->taskList->taskListId()->nodeName())->answerWithDataProcessingCompleted();
     $this->receiveMessage($newEvent, $workflowEngine);
 }
示例#7
0
 /**
  * @test
  */
 public function it_only_accepts_error_code_greater_than_399_otherwise_it_uses_500_as_code()
 {
     $wfMessage = $this->getTestWorkflowMessage();
     $exception = new \DomainException("Data cannot be found", 399);
     $message = LogMessage::logException($exception, $wfMessage);
     $this->assertEquals('Data cannot be found', $message->technicalMsg());
     $this->assertTrue($message->isError());
     $this->assertEquals(500, $message->msgCode());
     $this->assertEquals($wfMessage->target(), $message->origin());
     $this->assertTrue($wfMessage->processTaskListPosition()->equals($message->processTaskListPosition()));
     $this->assertTrue(isset($message->msgParams()['trace']));
     $this->assertEquals(NodeName::defaultName()->toString(), $message->target());
 }