Skip to content
This repository was archived by the owner on May 20, 2019. It is now read-only.

Add support for topic schema defined as ServiceName:methodName #23

Merged
merged 8 commits into from
Jan 27, 2019

Conversation

anvasiliev
Copy link

@anvasiliev anvasiliev commented May 22, 2018

Topics which configured as schema="ServiceName:methodName" always are synchronous topic type (see \Magento\Framework\Communication\Config\ReflectionGenerator::generateTopicConfigForServiceMethod ) and is not possible to use with \Magento\AsynchronousOperations\Model\MassConsumer

PR added new optional attribute "is_synchronous" in to urn:magento:framework:Communication/etc/communication.xsd which identify is topic are sync or async.
If topic attribute not defined or attribute value "true": topic are sync.
In case when topic attribute value "false": topic are async type, even if schema attribute or request+response attributes defined.

Example config:
communication.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Communication/etc/communication.xsd">
<!-- ASYNC topics -->
    <topic name="async.topic.example.1" schema="Magento\Example\Api\EntityRepositoryInterface::save" is_synchronous="false">
        <handler name="async" type="Magento\Example\Api\EntityRepositoryInterface" method="save"/>
    </topic>
   <topic name="async.topic.example.2" request="string" response="string" is_synchronous="false">
        <handler name="async" type="Magento\Example\Api\EntityRepositoryInterface" method="save"/>
    </topic>

<!-- SYNC topics -->
    <topic name="sync.topic.example.3" request="string" response="string" is_synchronous="true">
        <handler name="async" type="Magento\Example\Api\EntityRepositoryInterface" method="save"/>
    </topic>
<topic name="sync.topic.example.4" request="string" response="string">
        <handler name="async" type="Magento\Example\Api\EntityRepositoryInterface" method="save"/>
    </topic>
<topic name="sync.topic.example.5" schema="Magento\Example\Api\EntityRepositoryInterface">
        <handler name="async" type="Magento\Example\Api\EntityRepositoryInterface" method="save"/>
    </topic>
</config>

queue_topology.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework-message-queue:etc/topology.xsd">
    <exchange name="magento" type="topic" connection="amqp">
        <binding id="async.operations.all" topic="async.#" destinationType="queue" destination="async.operations.all"/>
    </exchange>
</config>

queue_consumer.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework-message-queue:etc/consumer.xsd">
    <consumer name="async.operations.all" queue="async.operations.all" connection="amqp"
              consumerInstance="Magento\AsynchronousOperations\Model\MassConsumer"/>
</config>

@magento-cicd2
Copy link

magento-cicd2 commented May 22, 2018

CLA assistant check
All committers have signed the CLA.

@magento-cicd2
Copy link

CLA assistant check
Thank you for your submission, we really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.


Vasiliev.A seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account.

Copy link

@paliarush paliarush left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please explain the purpose of the task, not clear from the PR description.

use Magento\AsynchronousOperations\Model\ConfigInterface;
use Magento\Framework\Communication\ConfigInterface as CommunicationConfig;

class CompositeReader

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add class documentation

class CompositeReader
{
/**
* Topics with type schema is always are sync

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Description does not sound right, please correct

@vrann
Copy link
Contributor

vrann commented Jun 27, 2018

@anvasiliev the problem described in bug was more related to the fact that in \Magento\Framework\MessageQueue\Consumer the topic type definition CommunicationConfig::TOPIC_REQUEST_TYPE_METHOD is supported: https://github.com/magento/bulk-api-ce/blob/2.3-develop/lib/internal/Magento/Framework/MessageQueue/Consumer.php#L135

While it is not supported here https://github.com/magento/bulk-api-ce/blob/2.3-develop/app/code/Magento/AsynchronousOperations/Model/MassConsumer.php#L109

Also, I don't think we need a plugin to convert topic to asynchronous, because all topics generated with async prefix will be defined using request type TOPIC_REQUEST_TYPE_CLASS.

But in case if somebody uses MassConsumer to process some other queue defined manually throughthe communication.xml, the support of TOPIC_REQUEST_TYPE_METHOD will be important

magento-engcom-team pushed a commit that referenced this pull request Aug 1, 2018
@nuzil nuzil requested a review from vkublytskyi August 24, 2018 15:29
@@ -143,7 +144,7 @@ protected function extractTopics($config)
} elseif ($requestSchema) {
$output[$topicName] = [
Config::TOPIC_NAME => $topicName,
Config::TOPIC_IS_SYNCHRONOUS => false,
Config::TOPIC_IS_SYNCHRONOUS => $isSynchronous ?? false,
Copy link

@paliarush paliarush Sep 4, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How can this request be synchronous? Please provide an example.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Request will be synchronous in next etc/communication.xml configs:

  1. Topic attributes "request" and "response" are both defined, attribute "is_synchronous" not defined or "true".
    <topic name="example.sync.topic" request="Magento\Example\Api\Data\EntityInterface" response="Magento\Example\Api\Data\EntityInterface"> <handler name="handler" type="Magento\Example\Api\EntityRepositoryInterface" method="save"/> </topic>
  2. Topic attribute "schema" defined and attribute "is_synchronous" not defined or "true"
    <topic name="example.sync.topic" schema="Magento\Example\Api\EntityRepositoryInterface::save"> <handler name="handler" type="Magento\Example\Api\EntityRepositoryInterface" method="save"/> </topic>

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@anvasiliev, seems there is a bug in the implementation. If is_synchronous is missed then extractTopicIsSynchronous return null which is treated as false. To avoid such issue better always return boolean from extractTopicIsSynchronous.

Also, I suppose, @paliarush question was about what is the reason to support asynchrony for topics that only send data and don't expect any response. Looks like for the last elseif ($requestSchema) we should always have Config::TOPIC_IS_SYNCHRONOUS => false regardless attribute value.

Config::TOPIC_REQUEST => $methodMetadata[Config::SCHEMA_METHOD_PARAMS],
Config::TOPIC_REQUEST_TYPE => Config::TOPIC_REQUEST_TYPE_METHOD,
Config::TOPIC_RESPONSE => $returnType,
Config::TOPIC_HANDLERS => $handlers
?: [self::DEFAULT_HANDLER => $methodMetadata[Config::SCHEMA_METHOD_HANDLER]]
? : [self::DEFAULT_HANDLER => $methodMetadata[Config::SCHEMA_METHOD_HANDLER]]
Copy link

@paliarush paliarush Sep 4, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this is an accidental change.

];
}

/**
* Generate topic name based on service type and method name.
*
* Perform the following conversion:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There should be an empty line between short and long descriptions.

$serviceType,
$serviceMethod,
$handlers = [],
$isSynchronous = null

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this already used anywhere?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

was not used anywhere. Fixed in last commit

Copy link

@paliarush paliarush left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please address comments above and cover with tests.

Copy link
Collaborator

@vkublytskyi vkublytskyi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please review comments and failed integration tests

* @param \DOMNode $topicNode
* @return boolean|null
*/
protected function extractTopicIsSynchronous($topicNode)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As this is new method it should be private

$attributeName = Config::TOPIC_IS_SYNCHRONOUS;
$topicAttributes = $topicNode->attributes;
if (!$topicAttributes->getNamedItem($attributeName)) {
return null;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please avoid methods with multiple return types. If some value should be applied by default this is the best place to define it. With this PHP return type declaration should be used for new code

private function extractTopicIsSynchronous($topicNode): bool

return null;
}
$value = $topicAttributes->getNamedItem($attributeName)->nodeValue;
$isSynchronous = filter_var($value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If XML file contains inappropriate value it should lead to an exception. Ideally, such case should be avoided by providing corresponding restrictions in XSD file.

@@ -143,7 +144,7 @@ protected function extractTopics($config)
} elseif ($requestSchema) {
$output[$topicName] = [
Config::TOPIC_NAME => $topicName,
Config::TOPIC_IS_SYNCHRONOUS => false,
Config::TOPIC_IS_SYNCHRONOUS => $isSynchronous ?? false,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@anvasiliev, seems there is a bug in the implementation. If is_synchronous is missed then extractTopicIsSynchronous return null which is treated as false. To avoid such issue better always return boolean from extractTopicIsSynchronous.

Also, I suppose, @paliarush question was about what is the reason to support asynchrony for topics that only send data and don't expect any response. Looks like for the last elseif ($requestSchema) we should always have Config::TOPIC_IS_SYNCHRONOUS => false regardless attribute value.

@vkublytskyi
Copy link
Collaborator

Code looks good. PR will be merged if manual QA doesn't discover bugs.

@nuzil nuzil self-requested a review January 16, 2019 08:46
@magento-engcom-team magento-engcom-team merged commit 4de1d94 into magento:2.3-develop Jan 27, 2019
@ghost
Copy link

ghost commented Jan 27, 2019

Hi @anvasiliev, thank you for your contribution!
Please, complete Contribution Survey, it will take less than a minute.
Your feedback will help us to improve contribution process.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants