public function create($data) { if (!array_key_exists("collect_data_trigger", $data)) { return new ApiProblemResponse(new ApiProblem(422, 'Root key collect_data_trigger missing in request data')); } $data = $data["collect_data_trigger"]; if (!array_key_exists('processing_type', $data)) { return new ApiProblemResponse(new ApiProblem(422, 'Key processing_type is missing')); } $processingType = $data['processing_type']; if (!class_exists($processingType)) { return new ApiProblemResponse(new ApiProblem(422, 'Provided processing type is unknown')); } try { Assertion::implementsInterface($processingType, 'Prooph\\Processing\\Type\\Type'); } catch (\InvalidArgumentException $ex) { return new ApiProblemResponse(new ApiProblem(422, 'Provided processing type is not valid')); } $wfMessage = WorkflowMessage::collectDataOf($processingType::prototype(), __CLASS__, $this->ProcessingConfig->getNodeName()); $this->messageLogger->logIncomingMessage($wfMessage); $this->workflowEngine->dispatch($wfMessage); /** @var $response Response */ $response = $this->getResponse(); $response->getHeaders()->addHeaderLine('Location', $this->url()->fromRoute('prooph.link/processor_proxy/api/messages', ['id' => $wfMessage->uuid()->toString()])); $response->setStatusCode(201); return $response; }
/** * @test */ public function it_injects_target_handler_to_command_dispatch_when_command_is_a_workflow_message() { $message = WorkflowMessage::collectDataOf(UserDictionary::prototype(), 'test-case', NodeName::defaultName()); $commandDispatch = new CommandDispatch(); $commandDispatch->setCommand($message); $router = new SingleTargetMessageRouter($this->getTestWorkflowProcessor()); $router->onRouteCommand($commandDispatch); $this->assertSame($this->getTestWorkflowProcessor(), $commandDispatch->getCommandHandler()); }
/** * @test */ public function it_handles_a_collect_data_message() { $taskListPosition = TaskListPosition::at(TaskListId::linkWith(NodeName::defaultName(), ProcessId::generate()), 2); $wfMessage = WorkflowMessage::collectDataOf(UserDictionary::prototype(), 'test-case', NodeName::defaultName()); $wfMessage->connectToProcessTask($taskListPosition); $this->workflowMessageHandler->handleWorkflowMessage($wfMessage); $this->assertSame($wfMessage, $this->workflowMessageHandler->lastCollectDataMessage()); $this->assertInstanceOf('Prooph\\Processing\\Message\\LogMessage', $this->lastProcessingMessage); }
/** * @test */ public function it_invokes_processing_command_on_workflow_message_handler() { $wfCommand = WorkflowMessage::collectDataOf(UserDictionary::prototype(), 'test-case', NodeName::defaultName()); $commandBus = new CommandBus(); $commandRouter = new CommandRouter(); $commandRouter->route($wfCommand->messageName())->to($this->workflowMessageHandler); $commandBus->utilize($commandRouter); $commandBus->utilize(new HandleWorkflowMessageInvokeStrategy()); $commandBus->dispatch($wfCommand); $this->assertSame($wfCommand, $this->workflowMessageHandler->lastWorkflowMessage()); }
public function __invoke(Route $route, AdapterInterface $console) { $consoleWriter = new ConsoleWriter($console); $consoleWriter->deriveVerbosityLevelFrom($route); $processingType = $route->getMatchedParam('type'); if (!class_exists($processingType)) { $consoleWriter->writeError(sprintf('Class %s not found', $processingType)); exit(self::INVALID_PROCESSING_TYPE); } try { $env = $this->loadEnvironment($route, $consoleWriter); $message = WorkflowMessage::collectDataOf($processingType::prototype(), __CLASS__, $env->getNodeName()); $consoleWriter->writeInfo('Start workflow with message: ' . $message->messageName()); $env->getWorkflowProcessor()->receiveMessage($message); $consoleWriter->writeSuccess('Message successfully processed'); return 0; } catch (\Exception $ex) { $consoleWriter->writeException($ex); return self::MESSAGE_PROCESSING_FAILED; } }
/** * @test */ public function it_collects_the_oldest_user_by_using_order_by_age() { $taskListPosition = TaskListPosition::at(TaskListId::linkWith(NodeName::defaultName(), ProcessId::generate()), 1); $metadata = ['order_by' => 'age DESC']; $message = WorkflowMessage::collectDataOf(TestUser::prototype(), 'test-case', 'localhost', $metadata); $message->connectToProcessTask($taskListPosition); $this->tableGateway->handleWorkflowMessage($message); $this->assertInstanceOf('Prooph\\Processing\\Message\\WorkflowMessage', $this->messageReceiver->getLastReceivedMessage()); /** @var $wfMessage WorkflowMessage */ $wfMessage = $this->messageReceiver->getLastReceivedMessage(); $user = $wfMessage->payload()->toType(); $this->assertInstanceOf('ProophTest\\Link\\SqlConnector\\DataType\\TestUser', $user); $this->assertEquals('Donald Duck', $user->property('name')->value()); }
/** * @test */ public function it_sets_wf_message_target_to_target_defined_in_the_process_task() { $task = ProcessData::address('test-target', ['Prooph\\ProcessingTest\\Mock\\TargetUserDictionary']); $process = LinearProcess::setUp(NodeName::defaultName(), [$task]); $wfm = WorkflowMessage::collectDataOf(UserDictionary::prototype(), 'test-case', NodeName::defaultName()); $answer = $wfm->answerWith(UserDictionary::fromNativeValue(['id' => 1, 'name' => 'John Doe', 'address' => ['street' => 'Main Street', 'streetNumber' => 10, 'zip' => '12345', 'city' => 'Test City']])); $this->commandRouter->route(MessageNameUtils::getProcessDataCommandName('Prooph\\ProcessingTest\\Mock\\TargetUserDictionary'))->to($this->workflowMessageHandler); $process->perform($this->workflowEngine, $answer); $receivedMessage = $this->workflowMessageHandler->lastWorkflowMessage(); $this->assertEquals('test-target', $receivedMessage->target()); }
/** * @return array */ public function provideEntries() { $wfStartMessage = WorkflowMessage::collectDataOf(TestUser::prototype(), 'test-case', 'localhost'); $startMessageLogEntry = MessageLogEntry::logMessage($wfStartMessage); $startMessageLogEntryWithAssignedProcessId = MessageLogEntry::logMessage($wfStartMessage); $startMessageLogEntryWithAssignedProcessId->assignIdOfStartedProcess(ProcessId::generate()); $startMessageLogEntryWithAssignedProcessIdSucceed = MessageLogEntry::logMessage($wfStartMessage); $startMessageLogEntryWithAssignedProcessIdSucceed->assignIdOfStartedProcess(ProcessId::generate()); $startMessageLogEntryWithAssignedProcessIdFailed = MessageLogEntry::logMessage($wfStartMessage); $startMessageLogEntryWithAssignedProcessIdFailed->markAsFailed("Starting process failed"); $wfMessage = WorkflowMessage::collectDataOf(TestUser::prototype(), 'test-case', 'localhost'); $taskListPosition = TaskListPosition::at(TaskListId::linkWith(NodeName::defaultName(), ProcessId::generate()), 1); $wfMessage->connectToProcessTask($taskListPosition); $normalMessageLogEntryPending = MessageLogEntry::logMessage($wfMessage); $normalMessageLogEntrySucceed = MessageLogEntry::logMessage($wfMessage); $normalMessageLogEntrySucceed->markAsSucceed(); $normalMessageLogEntryFailed = MessageLogEntry::logMessage($wfMessage); $normalMessageLogEntryFailed->markAsFailed("Processing failed"); return [[$startMessageLogEntry], [$startMessageLogEntryWithAssignedProcessId], [$startMessageLogEntryWithAssignedProcessIdSucceed], [$startMessageLogEntryWithAssignedProcessIdFailed], [$normalMessageLogEntryPending], [$normalMessageLogEntrySucceed], [$normalMessageLogEntryFailed]]; }
/** * @TODO: Improve test, the merge_files strategy is not the best choice for the tested scenario * @test */ public function it_collects_users_from_multiple_json_files_using_merge_files_strategy() { $taskListPosition = TaskListPosition::at(TaskListId::linkWith(NodeName::defaultName(), ProcessId::generate()), 1); $metadata = ['filename_pattern' => '/^testuser_.+\\.json$/', 'path' => $this->getTestDataPath(), 'file_type' => 'json', 'fetch_mode' => FileGateway::META_FETCH_MODE_MULTI_FILES, 'merge_files' => true]; $message = WorkflowMessage::collectDataOf(TestUser::prototype(), NodeName::defaultName()->toString(), 'file-connector', $metadata); $message->connectToProcessTask($taskListPosition); $this->fileGateway->handleWorkflowMessage($message); $this->assertInstanceOf('Prooph\\Processing\\Message\\WorkflowMessage', $this->messageReceiver->getLastReceivedMessage()); /** @var $wfMessage WorkflowMessage */ $wfMessage = $this->messageReceiver->getLastReceivedMessage(); $user = $wfMessage->payload()->toType(); $this->assertInstanceOf('ProophTest\\Link\\FileConnector\\DataType\\TestUser', $user); //The FileGateway should have found both user files. It uses scandir with descending order so //testuser_max_mustermann.json should be handled before testuser_john_doe.json. //When merging the data of both users John Doe overrides Max Mustermann. $this->assertEquals('John Doe', $user->property('name')->value()); }
/** * @test */ public function it_dispatches_a_service_bus_message() { $wfMessage = WorkflowMessage::collectDataOf(UserDictionary::prototype(), 'test-case', 'test-target', []); $sbMessage = $wfMessage->toServiceBusMessage(); $this->workflowEngine->dispatch($sbMessage); $this->assertInstanceOf(get_class($wfMessage), $this->receivedMessage); }
/** * @param CollectData $collectData * @param TaskListPosition $taskListPosition * @param WorkflowEngine $workflowEngine * @param WorkflowMessage $previousMessage */ protected function performCollectData(CollectData $collectData, TaskListPosition $taskListPosition, WorkflowEngine $workflowEngine, WorkflowMessage $previousMessage = null) { $metadata = $collectData->metadata(); if (!is_null($previousMessage)) { $metadata = ArrayUtils::merge($previousMessage->metadata(), $collectData->metadata()); } $workflowMessage = WorkflowMessage::collectDataOf($collectData->prototype(), $this->taskList->taskListId()->nodeName(), $collectData->source(), $metadata); $workflowMessage->connectToProcessTask($taskListPosition); try { $workflowEngine->dispatch($workflowMessage); } catch (CommandDispatchException $ex) { $this->receiveMessage(LogMessage::logException($ex->getPrevious(), $workflowMessage), $workflowEngine); } catch (\Exception $ex) { $this->receiveMessage(LogMessage::logException($ex, $workflowMessage), $workflowEngine); } }
/** * @return WorkflowMessage */ private function getTestWorkflowMessage() { $taskListPosition = TaskListPosition::at(TaskListId::linkWith(NodeName::defaultName(), ProcessId::generate()), 1); $wfMessage = WorkflowMessage::collectDataOf(UserDictionary::prototype(), 'test-case', 'message-handler'); $wfMessage->connectToProcessTask($taskListPosition); return $wfMessage; }
/** * @test */ public function it_creates_a_command_bus_that_dispatches_a_message_to_a_workflow_message_handler() { $env = Environment::setUp(["processing" => ["channels" => ['message_handler_channel' => ['targets' => ["test_command_handler"]]]]]); $messageHandler = new TestWorkflowMessageHandler(); $env->services()->set('test_command_handler', $messageHandler); $commandBus = $env->services()->get("processing.command_bus.test_command_handler"); $message = WorkflowMessage::collectDataOf(UserDictionary::prototype(), 'test-case', NodeName::defaultName()); $commandBus->dispatch($message); $this->assertSame($message, $messageHandler->lastWorkflowMessage()); }
/** * @test */ public function it_translates_itself_to_service_bus_message_and_back() { $wfMessage = WorkflowMessage::collectDataOf(UserDictionary::prototype(), 'test-case', NodeName::defaultName()->toString(), array('metadata' => true)); $sbMessage = $wfMessage->toServiceBusMessage(); $this->assertInstanceOf('Prooph\\Common\\Messaging\\RemoteMessage', $sbMessage); $copyOfWfMessage = WorkflowMessage::fromServiceBusMessage($sbMessage); $this->assertInstanceOf('Prooph\\Processing\\Message\\WorkflowMessage', $copyOfWfMessage); $this->assertEquals(MessageNameUtils::MESSAGE_NAME_PREFIX . 'proophprocessingtestmockuserdictionary-collect-data', $copyOfWfMessage->messageName()); $this->assertNull($copyOfWfMessage->payload()->extractTypeData()); $this->assertEquals(array('metadata' => true), $copyOfWfMessage->metadata()); $this->assertEquals(MessageNameUtils::COLLECT_DATA, $copyOfWfMessage->messageType()); $this->assertEquals('test-case', $copyOfWfMessage->origin()); $this->assertEquals(NodeName::defaultName()->toString(), $copyOfWfMessage->target()); }
/** * @param WorkflowMessage $workflowMessage * @param WorkflowEngine $workflowEngine */ private function startSubProcessForEachChunk(WorkflowMessage $workflowMessage, WorkflowEngine $workflowEngine) { $taskListEntry = $this->taskList->getNextNotStartedTaskListEntry(); $this->recordThat(TaskEntryMarkedAsRunning::at($taskListEntry->taskListPosition())); $this->processingCollection = true; /** @var $task RunSubProcess */ $task = $taskListEntry->task(); $metadata = $workflowMessage->metadata(); $currentOffset = 0; $currentLimit = (int) $metadata[self::META_LIMIT]; $totalItems = (int) $metadata[self::META_TOTAL_ITEMS]; //May start message was performed as a count only message so we unset this instruction to tell //the workflow message handler that it should collect the data now. unset($metadata[self::META_COUNT_ONLY]); do { $typeClass = $workflowMessage->payload()->getTypeClass(); $metadata[self::META_OFFSET] = $currentOffset; $metadata[self::META_LIMIT] = $currentLimit; $collectChunk = WorkflowMessage::collectDataOf($typeClass::prototype(), $this->taskList->taskListId()->nodeName(), $task->targetNodeName(), $metadata); $collectChunk->connectToProcessTask($taskListEntry->taskListPosition()); $this->recordThat(MultiPerformTaskWasStarted::at($taskListEntry->taskListPosition())); $this->performRunSubProcess($task, $taskListEntry->taskListPosition(), $workflowEngine, $collectChunk); $currentOffset = $currentOffset + $currentLimit; } while ($currentOffset + $currentLimit <= $totalItems); $this->processingCollection = false; }