Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remote Code Invoker Design Doc #37

Closed
wants to merge 9 commits into from

Conversation

AlexMaxHorkun
Copy link
Contributor

@AlexMaxHorkun AlexMaxHorkun commented Oct 26, 2018

Design for remote code execution as a part of distributed Magento

* Other application state spoofing may be required for seamless remote execution of services
### Functional requirements
* Invoker's code is a part of Magento\Framework namespace
* Invoker is able to call any class' method
Copy link
Contributor

Choose a reason for hiding this comment

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

Don't think that such freedom is acceptable

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@antonkril Updated the doc

proper deserialization by the caller
* Remote call response can provide either serialized method call result or serialized exception to be
rethrow in order to emulate local method call
* Remote calls are done in a synchronous manner because in order for
Copy link
Contributor

Choose a reason for hiding this comment

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

Such limitation will introduce misleading abstraction of local call. Also this contradicts the main design document

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@antonkril I've added explanations for this issue

Copy link
Contributor

Choose a reason for hiding this comment

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

I understood your explanation, but the conversation is about making new services asynchronous, not existing ones.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You mean you want our new service contracts look like below and client code always using other services in asynchronous manner?

interface NewEntityRepositoryInterface
{
    public function save(NewEntityInterface $entity): Promise;
}

Local implementations would almost always be executed in a synchronous manner and using them would just severely complicate our code. PHP does not support async code execution in it's core, and making some of the code async will most likely force all the client code working with such services be async. I mean look at node.js and it's callback hell, do we want that in Magento?

@AlexMaxHorkun
Copy link
Contributor Author

I have added "Explanations" section to the document where some of the controversial points are being explained

proper deserialization by the caller
* Remote call response can provide either serialized method call result or serialized exception to be
rethrow in order to emulate local method call
* Remote calls are done in a synchronous manner because in order for
Copy link
Contributor

Choose a reason for hiding this comment

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

I understood your explanation, but the conversation is about making new services asynchronous, not existing ones.

If the remote call to _ProductRepositoryInterface_ service was done via RESTful (or GraphQL) web API the _incrOrdederedCount_ would have
to be exposed as Web API and could be requested via HTTP by anyone and independently from context which we cannot afford since we can't just increase the counter without an order happening so only another service responsible for orders may call _incrOrdederedCount_.

If done via the Invoker the _incrOrdederedCount_ wouldn't be exposed to be requested by HTTP clients via web API and wouldn't show up on
Copy link
Contributor

Choose a reason for hiding this comment

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

There is no difference because Invoker makes the method exposed to all services, if I understand the proposal correctly.
Keep in mind that client-facing Web APIs are not the same as service-facing (inter-network) Web APIs. Only limited list of Web APIs (explicitly declared) will be exposed to the client on the BFF side. All other APIs will be available for services only.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

With RPC style communication there would be no need to re-declare our web API endpoints and there would be a clear differentiation between web API endpoints for outside world and inner-network

If the remote call to _ProductRepositoryInterface::decrOrderedCount_ was done via RESTful web API the exposed endpoint would have
ACL configured for it so it requires _Catalog edit access_ from admins, but our current admin only has access to _orders_ and the call would fail. However if the Catalog domain modules were not remote and the _ProductRepositoryInterface::decrOrderedCount_ call was made then no ACL validation would occur and we would save the order successsfully.

With Invoker such ACL validations wouldn't occur and the remote call would be completed just as if it was local.
Copy link
Contributor

Choose a reason for hiding this comment

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

ACL for Web API should be revisited. It's not necessary to introduce another type of APIs (invoker-based) to modify access.
Authentication and authorization can be done on API Gateway level, and in-network calls between services can be done w/o additional validation. Or for better security, there can be additional validation on each service, which will be probably similar to what you propose for the invoker. It depends on how we want to implement it.

HTTP method/URL pair for external systems - we don't need that when writing a proxy service since we
would always already have class and method's names, the only other thing existing RESTful Web API mechanism
provides is it's serializer and it will be reused in the _Remote Code Invoker_
* When an exception occurs during a service call via RESTful API the response does not contain
Copy link
Contributor

Choose a reason for hiding this comment

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

Looks more like an issue with error reporting for Web APIs.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

not really, clientside and 3rd-party systems wouldn't care for exception classes in responses of RESTful APIs

@buskamuza buskamuza mentioned this pull request Nov 9, 2018

Depending on whether _BModule_ or _BModuleProxy_ is deployed on the local node _ServiceBInterface_ will either
work locally or remotely.
### Why not just use cURL and existing Web APIs
Copy link
Member

Choose a reason for hiding this comment

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

I was thinking that service mesh will handle retries

* Multiple remote sources can be configured and assigned unique IDs
* Each HTTP request to remote sources is signed using unique source's key, timestamp and request's attributes
* Each remote call must be given unique ID to be used by retries mechanism
* Timeout limit and retries count can be configured globally and for each call
Copy link
Member

Choose a reason for hiding this comment

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

I think service mesh should handle these things.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

service mash is a separate system which is acting as a proxy between inter-service communications and, yes, provides retries and data consistency. I haven't found a mention of such system in Anton's docs and nor do we need such system - they only make sense when different services use different languages/frameworks etc. And we are going to use PHP + Magento on all of our services.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If what you were meaning to say is that we need a separate entity in our codebase to handle retries, data consistency etc - this document is in fact describing such entity (invoker = service mesh)

Copy link
Member

Choose a reason for hiding this comment

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

Service mesh can solve many problems related to deployment and communication for us: service registration, routing, load balancing, circuit breaking, retries, statistics and monitoring, etc. Retries logic is complicated and I would suggest not to implement it ourselves.

$promise->then(function (\Magento\ModuleNameApi\Data\ResultDTOInterface $result) use (&$remoteResult) {
$remoteResult = $result;
});
$promise->wait();
Copy link
Member

Choose a reason for hiding this comment

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

I wonder if we need to have different interfaces for synchronous and asynchronous communication. Developer would know how communication happens. And we will not have to wait for result of asynchronous operation, one of the benefits of async operations is that we don't need to wait for the response and it can be performed quickly.

and in an asynchronous manner for new services to be able to interact with other services with remote invoking in mind
* Each Magento instance that can be used for remote calls (_Magento server_)
has it's own unique key for signing requests
* Remote calls can be disabled in a Magento server
Copy link
Member

Choose a reason for hiding this comment

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

What is Magento server, instance/installation?

* Each Magento instance that can be used for remote calls (_Magento server_)
has it's own unique key for signing requests
* Remote calls can be disabled in a Magento server
* Authenticated user's information (ID and type) is passed from caller
Copy link
Member

Choose a reason for hiding this comment

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

Will it be added by the remote implementation of the service?

Response body will contain serialized service call result or a serialized thrown exception encoded in json.

#### Why RESTful web API should not be used as the network gateway for the invoker
* Not all service contracts are exposed as web API and nor should they be (for security and workflow reasons)
Copy link
Member

Choose a reason for hiding this comment

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

We will have BFF that would expose public API. API of the services can be exposed and will be protected by private network.

@buskamuza
Copy link
Contributor

Requires tech vision for inter services communication first.

@melnikovi
Copy link
Member

Closing as topic is covered in #50.

@melnikovi melnikovi closed this Feb 4, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants