I want to build a like-service with a grpc api.
I saw couple of examples and they all only had one service contract (apparently for in and out).
When I build it like this, can I send GET and POST to this service, or do I need two contracts for it?
service LikeService{
rpc LikePicture(PictureId) returns (Likes) {}
}
HTTP verbs|methods (GET, POST etc.) aren't accessible to gRPC developers (and everything's a POST).
If you're anticipating POST as a way to submit likes and GET as a way to retrieve likes, you may want to consider something of the form:
service LikeService{
rpc AddLike(PictureId) returns () {}
rpc GetLikes(PictureId) returns (Likes) {}
}
NOTE The AddLike method need not return anything if a successful call provides sufficient information.
Related
I want to standup an endpoint /foo which is a synchronous endpoint for clients but the response is dependent on a callback /foo_callback being called on the app as a result of the request to the synchronous endpoint.
to elaborate the workflow:
Flow diagram
I havent decided on a technology to use so ideally would look for a recommendation.
High level what I am thinking of is starting an async thread in the request handler and check for an update on a singleton map to see if the server has responded but I am wondering if there is a better way
I dont have control over the client and cannot really use websocket or long polling.
I have a question microservice architecture about services working interrelated wih each other.
For example;
Let's think the below senario in e-commerce.
We have BuyProduct Endpoint and request to this endpoint.
Browser request
BuyProduct executes.
BuyProduct has three service calls
1)Payment Service Call
if payment service fail
return false;
else
continue;
2)Stock Service Call
if stock service fail
return false;
else
continue;
3)Account Service Call
if account service fail
return false;
else
continue;
Return to the browser success or fail
In this example,I assumed success or fail state when passing from a service call to another service.
But for example there might be a situation in which values returned from payment service call to stock service call request.
My question is ;
If we have message broker and want to make async architecture with a message broker(like rabbitmq or another).How can we implement this senario ? Will this solution be valid or Is there any solution?
What is the best practice ?
I googled but could not find a solution that satisfied me?
I am not sure that my solution I think is true.(I mean rest sync architecture)
If browser waits for immediate result and we want to gurantee our processes finish successfully or fail ,What will happen ?
When we think this senario as all-or-none,What can we do ?
If you use a message broker to make this async, you will have to deal with the concept of eventual consistency. This means that for a brief period (hopefully) of time, you would have processed the payment, but have not updated the stock and the account statuses.
Your code must then be able to handle the inconsistencies. For example, there is only one item left and 2 customer both bought the item at the same time. The calls to Payment Service would work for both but one of the calls to the Stock Service would fail.
A microservice pattern that helps to manage such data consistency problems is called Saga pattern. A saga is basically a mechanism to coordinate multiple microservices to work together in a manner that ensures data remain consistent. Since you mentioned that you are exploring the use of a message broker, you may want to look at the choreography based approach.
I've got a project written in Symfony 4 (can update to the latest version if needed). In it I have a situation similar to this:
There is a controller which sends requests to an external system. It goes through records in the DB and sends a request for every row. To do that there is an MagicApiConnector class which connects to the external system, and for every request there is a XxxRequest class (like FooRequest, BarRequest, etc).
So, something like this general:
foreach ( $allRows as $row ) {
$request = new FooRequest($row['a'], $row['b']);
$connector->send($request);
}
Now in order to do all the parameter filling magic, the requests need to access a service which is defined in Symfony's DI. The controller itself neither knows nor cares about this service, but the requests need it.
How can my request classes access this service? I don't want to set it as a dependency of the controller - I could, but it kinda seems awkward, as the controller really doesn't care about it and would only pass it through. It's an implementation detail of the request, and I feel like it shouldn't burden the users of the request with this boilerplate requirement.
Then again, sometimes you need to make a sacrifice in the name of the greater good, so perhaps this is one of those cases? It feels like I'm "going against the grain" and haven't grasped some ideological concept.
Added: OK, the full gory details, no simplification.
This all is happening in the context of two homebrew systems. Let's call them OldApp and NewApp. Both are APIs and NewApp is calling into the OldApp. The APIs are simple REST/JSON style. OldApp is not built on Symfony (mostly even doesn't use a framework), the NewApp is. My question is about NewApp.
The authentication for OldApp APIs comes in three different flavors and might get more in the future if needed (it's not yet dead!) Different API calls use different authentication methods; sometimes even the same API call can be used with different methods (depending on who is calling it). All these authentication methods are also homebrew. One uses POST fields, another uses custom HTTP headers, don't remember about the third.
Now, NewApp is being called by an Android app which is distributed to many users. Android app actually uses both NewApp and OldApp. When it calls NewApp it passes along extra HTTP headers with authentication data for OldApp (method 1). Thus NewApp can impersonate the Android app user for OldApp. In addition, NewApp also needs to use a special command of OldApp that users themselves cannot call (a question of privilege). Therefore it uses a different authentication mechanism (method 2) for that command. The parameters for that command are stored in local configuration (environment variables).
Before me, a colleague had created the scheme of a APIConnector and APICommand where you get the connector as a dependency and create command instances as needed. The connector actually performs the HTTP request; the commands tell it what POST fields and what headers to send. I wish to keep this scheme.
But now how do the different authentication mechanisms fit into this? Each command should be able to pass what it needs to the connector; and the mechanisms should be reusable for multiple commands. But one needs access to the incoming request, the other needs access to configuration parameters. And neither is instantiated through DI. How to do this elegantly?
This sounds like a job for factories.
function action(MyRequestFactory $requestFactory)
{
foreach ( $allRows as $row ) {
$request = $requestFactory->createFoo($row['a'], $row['b']);
$connector->send($request);
}
The factory itself as a service and injected into the controller as part of the normal Symfony design. Whatever additional services that are needed will be injected into the factory. The factory in turn can provide whatever services the individual requests might happen to need as it creates the request.
I am using spring boot for developing services in my application.
I have a scenario where-in the request submitted to the back-end would take some time to complete.
To avoid waiting the client I want to return the response immediately with a message your request has been accepted. The request would be in progress in a background thread.
I see Spring provides the #Async annotation which can be used to create a separate processing thread from the main thread and using that I am able to offload the processing in a separate thread.
What I want to do is when I return the initial response as accepted I also want to provide the client with a tracking key/token which the client can later use to check the status of the request.
Since there can be multiple clients who would be accessing the service there should be a way of uniquely identifying each client's request from another.
I see there is no such feature in Spring Async or Future which can return a tracking id as such.
One possibility I see it to put the Future returned in HttpSession and later use that to check for the status by the client. But, I prefer not to use HttpSession and want my services to be stateless.
Is there any way/approach I can accomplish my requirement.
Thanks,
BS
Generate the key before calling the Async method, and pass it to the method:
String key = generateUniqueKey();
callAsyncMethod(key);
return key;
The Async method will have to persist the status of the execution somewhere (let's call it dataStore). When the client asks for the status using the key, you look it up on the dataStore and return it.
I've been recently investigating about Spring Integration and AMQP (RabbitMQ), as I need to communicate two applications (middleware and backend) with async approach, so that the middleware doesn't block when receiving client calls.
I first followed the simpler approach of implementing this in a synchronous, this meaning that I have a gateway interface and an outbound gateway (with requiresReply=true) on the middleware, and then an inbound gateway and a service activator on the backend. This initial approach works well (I've used Spring Integration XML config).
Now I need clarification on the approach to follow to make this work in an async way.
By looking at the RabbitMQ Tutorial 6, it's better to work with a callback queue and a correlationId, and per what I understood, this would be similar to calling Spring RabbitTemplate's convertAndSend() and then receive(), instead of convertSendAndReceive() (which would block until response is received).
I've checked the Spring Integration docs, where I need to replace the gateway interface on the middleware for it to return Future or ListenableFuture.
Async Gateway
Once that's done, I also looked at the documentation for the outbound gateway, where it says that it can work together with the RabbitTemplate to manage the correlationID and replyTo message attributes.
My questions are:
In order to make this work with an async approach, should I keep working with outbound/inbound gateways, instead of outbound/inbound message converters?
In case of following the outbound/inbound message converters approach (which sounds to me similar to what the RabbitMQ tutorial shows), how do I associate the Future on the gateway interface with the result coming back from with inbound channel adapter?
To be honest you don't provide an original business requirement. It might be a fact that there is really no reason to get deal with this async handsoff, because you have a #Gateway as an entry point which is thread-free and even if it is blocked to wait for the reply it doesn't impact other threads which may perform similar sendAndReceive operation. In most cases it is really just enough to do everything within the same requestor thread and don't loose performance with shifting to the shared ThreadPoolExecutor.
Right, the Future allows you to free a caller a bit to be ready to accept new requests within the same thread.
Since it is a MessagingGateway and you want to have a reply anyway, there is a hook associated with the request - TemporaryReplyChannel header. That's why that <outbound-gateway> works properly: it place its blocking reply to that channel for the gateway's return (or for FutureTask#set()).
I'd say that we can achieve the same TemporaryReplyChannel gain with that your async reply requirement.
You should use inbound/outbound channel adapter pair.
Before send the message to the <int-amqp:outbound-channel-adapter> you should do this <header-channels-to-string> for the <header-enricher>.
The server side maybe the same - <int-amqp:inbound-gateway>
You should use fixed replyQueue as a header for those message to send through the <int-amqp:outbound-channel-adapter>
the <int-amqp:inbound-channel-adapter> should be configured for that fixed replyQueue.
Both <int-amqp:outbound-channel-adapter> on client side and <int-amqp:inbound-gateway> must be configured for the mapped-request-headers="*" to allow to propagate that reply-channel header to the server and vise versa.
The <int-amqp:inbound-channel-adapter> on the client side will just send the reply to the reply-channel as it is for the <int-amqp:outbound-gateway>
You may need to take care about the correlationId manually, since <int-amqp:inbound-gateway> may require that to produce a reply properly.
Well, something like that...
HTH
Feel free to ask more questions. Or correct me if I misunderstood your question.