Is the design correct using WebFlux Framework? - spring

Have written a microservice(Using webFlux) which in turn calls three other microservices(Not using webflux). New microservice call the other three using flatmap. and controller is returning Mono . Is this correct Design. Do I need to pushlishOn?
Mono<String> result =service1.api(input)
.flatmap(innput-> service2.api).flatmap(input-> service3.api);
And Controller is also Returning Mono . Is the design correct. Will it be working in non-blocking way?

The publishOn method does not change code either into non-blocking or blocking code. All it does is force downstream operators to run in a different thread. However, if the service calls made within those threads are blocking, then you'll just be blocking another thread if you use publishOn.
So, to answer "Will it be working in non-blocking way", it actually depends on how you implemented service1.api(), service2.api() and service3.api(). If they synchronously fetch your data, then it will still be blocking, no matter what you do.
However, if you use the new WebClient API for example to reactively fetch your data from your three microservices properly, then yes, it should be non-blocking.

Related

At what point does the subscription take place? (spring webflux)

At what point does the spring webflux do the subscription? Everywhere I have read that there must be a subscription otherwise no change happens. In my short time with Spring Webflux, I have never seen a subscribe() neither in the controller or services.
My doubt is also when using flatMap(), map(),... etc.. at what point does the subscription take place?
What I have read does not really resolve my doubts.
public Flux method(){
....
myFlux.flatMap(data -> {
....
}).flatMap(e -> { .... });
}
I know this is an asynchronous issue, but each flatMap runs at the same time?...and so sometimes some data I have noticed is null.
It's the framework (spring-webflux) that subscribes to the returned Mono or Flux. For example if you use Netty (that's the default), then subscription happens here based on my debugging:
https://github.com/reactor/reactor-netty/blob/db27625064fc78f8374c1ef0af3160ec3ae979f4/reactor-netty-http/src/main/java/reactor/netty/http/server/HttpServer.java#L962
Also, this article might be of help to understand what happens when:
https://spring.io/blog/2019/03/06/flight-of-the-flux-1-assembly-vs-subscription
You need to call a .subscribe() or block() function after your flatmap. Here's an example.
Assuming that myFlux is of type Flux, the following will execute the subscription based on the example above
myFlux.subscribe(System.out::println);
Here's an explanation on a separate StackOverflow thread.
But in your method function, you are returning a Flux object - so it's up to the consumer of the method() function how it wants to subscribe to the Flux. You shouldn't be trying to subscribe to the Flux from within
The answer is: it depends.
For example, if this is a Spring Controller method, then it is the framework itself that subscribes to the Mono or Flux.
If it is a method that is triggered from time to time by a Scheduler, then you must explicitly subscribe to the Mono or Flux, otherwise, no processing will take place.
This means that if your application only exposes a REST API and no processing need to be triggered in any other way, then it is very likely that you will never need to explicitly subscribe to a Mono or Flux because Spring will take care of that by you.

Microservice Architecture: Can you eliminate the synchronous calls between services completely in a system?

Anywhere you read about Microservices, it says microservice should communicate asynchronously. It is understandable why asynchronous communication is preferred as it removes dependencies and provides low-coupling, and availability, etc.
Suppose, there is a common authorization service that is invoked every time a user calls an API. In this scenario you cannot move further util you have the response from the authorization service. Although you can call the authorization service asynchronously using Async IO, however, it is still a request/reply pattern.
Questions I have
Is possible to get rid of synchronous communication or more appropriately request/reply pattern in microservices-based system design?
Although it is possible to implement a reply/response pattern asynchronously through messaging and callbacks, which add significant overhead and latency but is it worth converting every request/reply to asynchronously?
If synchronous calls cannot be eliminated completely, then which scenarios it is ok to have synchronous calls among microservices?
I think the short answer for your question is: request-reply pattern doesn't mean synchronous. It can also be asynchronous. Which you already mentioned.
Long answer:
Request-Reply is just a principle. For example you send an email to a friend. The message contains data relevant to you and you are expecting a response but didn't say that explicitly. Your friend will see the email when he will get back from work and then he may or may not reply to you. Only you know that you need an answer from him.
Now there are a few options while waiting for your response. Either block your entire life until your friend responds (which will mean synchronous communication) either do something else until the response arrives in your inbox (which is asynchronous).
Now, to the point:
Is possible to get rid of synchronous communication or more appropriately request/reply pattern in microservices-based system design?
Yes, you already have answered that at the second point. Even though it is possible I think it should be used where it is required.
Although it is possible to implement a reply/response pattern asynchronously through messaging and callbacks, which add significant overhead and latency but is it worth converting every request/reply to asynchronously?
For the right scenario, yes. The messaging system have very good performances so the latency should not be an issue. When a latency problem occurs in a messaging system there are other options to improve it.
If synchronous calls cannot be eliminated completely, then which scenarios it is ok to have synchronous calls among microservices?
Yes.
There is one more thing that needs to be added. Synchronous doesn't always mean blocking. In a reactive world, if you make an HTTP call to another service the caller sends the request and then awaits for the response in a non-blocking manner. When the responses arrives, the caller is notified the the response has arrived and so the process continues. While "awaiting" the CPU can do other stuff.

Cannot use 'subscribe' or 'subscribeWith' with 'ReactorNettyWebSocketClient' in Kotlin

The Kotlin code below successfully connects to a Spring WebFlux server, sends a message and prints each message sent via the stream that is returned.
fun main(args: Array<String>) {
val uri = URI("ws://localhost:8080/myservice")
val client = ReactorNettyWebSocketClient()
val input = Flux.just(readMsg())
client.execute(uri) { session ->
session.send(input.map(session::textMessage))
.thenMany(
session.receive()
.map(WebSocketMessage::getPayloadAsText)
.doOnNext(::println) // want to replace this call
.then()
).then()
}.block()
}
In previous experience with Reactive programming I have always used subscribe or subscribeWith where the call to doOnNext occurs. However it will not work in this case. I understand that this is because neither returns the reactive stream in use - subscribe returns a Disposable and subscribeWith returns the Subscriber it received as a parameter.
My question is whether invoking doOnNext is really the correct way to add a handler to process incoming messages?
Most Spring 5 tutorials show code which either calls this or log, but some use subscribeWith(output).then() without specifying what output should be. I cannot see how the latter would even compile.
subscribe and subscribeWith should always be used right at the end of a chain of operators, not as intermediate operators.
Simon already provided the answer but I'll add some extra context.
When composing asynchronous logic with Reactor (and ReactiveX patterns) you build an end-to-end chain of processing steps, which includes not only the logic of the WebSocketHandler itself but also that of the underlying WebSocket framework code responsible for sending and receiving messages to and from the socket. It's very important for the entire chain to be connected together, so that at runtime "signals" will flow through it (onNext, onError, or onComplete) from start to end and communicate the final result, i.e where you have the .block() at the end.
In the case of WebSocket this looks a little daunting because you're essentially combining two or more streams into one. You can't just subscribe to one of those streams (e.g. for inbound messages) because that prevents composing a unified processing stream, and signals will not flow through to the end where the final outcome is expected.
The other side of this is that subscribe() triggers consumption on a stream whereas what you really want is to keep composing asynchronous logic in deferred mode, i.e. declaring all that will happen when data materializes. This is another reason why composing a single unified chain is important. So it can be triggered after it is fully declared.
In short the main difference with the imperative WebSocketHandler for the Servlet world, is that instead of it being a handler for individual messages, this is a handler for composing the complete streams. Here the handling of an individual message is just one step of the overall processing chain. So the only place to subscribe is at the very end, where .block() is, in order to kick off processing.
BTW since this question was first posted a few months ago, the documentation has been improved to provide more guidance on how to implement a WebSocketHandler.

why does spring cloud stream's #InboundChannelAdapter accept no parameters?

I'm trying to use spring cloud stream to send and receive messages on kafka. The examples for this use a simple example of using time stamps as the messages. I'm trying to go just one step further into a real world application when I ran into this blocker on the InboundChannelAdapter docs:
"A method annotated with #InboundChannelAdapter can't accept any parameters"
I was trying to use it like so:
#InboundChannelAdapter(value = ChannelManager.OUTPUT)
public EventCreated createCustomerEvent(String customerId, String thingId) {
return new EventCreated(customerId, thingId);
}
What usage am I missing? I imagine that when you want to create an event, you have some data that you want to use for that event, and so you would normally pass that data in via parameters. But "A method annotated with #InboundChannelAdapter can't accept any parameters". So how are you supposed to use this?
I understand that #InboundChannelAdapter comes from spring-integration, which spring-cloud-stream extends, and so spring-integration may have a different context in which this makes sense. But it seems un-intuitive to me (as does using an _INBOUND_ChannelAdapter for an output/producer/source)
Well, first of all the #InboundChannelAdapter is defined exactly in Spring Integration and Spring Cloud Stream doesn't extend it. That's false. Not sure where you have picked up that info...
This annotation builds something like SourcePollingChannelAdapter which provides a poller based on the scheduler and calls periodically a MessageSource.receive(). Since there is no any context and end-user can't effect that poller's behavior with his own arguments, the requirement for empty method parameters is obvious.
This #InboundChannelAdapter is a beginning of the flow and it is active. It does its logic on background without your events.
If you would like to call some method with parameters and trigger with that some flow, you should consider to use #MessagingGateway: http://docs.spring.io/spring-integration/reference/html/messaging-endpoints-chapter.html#messaging-gateway-annotation
How are you expecting to call that method? I think there was a miscommunication with your statement "stream extends integration" and Artem probably understood that we extend #InboundChannelAdatper
So, if you are actively calling this method, as it appears since you do have arguments that are passed to it, why not just using your source channel to send the data?
Usually sources do not require arguments as they are either push like the twitter stream that taps on twitter, listen for events and pushes them to the source channel, or they are polled, in which case, they are invoked on an interval defined via a poller.
As Artem pointed, if your intention is to call this method from your business flow, and deal with the return while triggering a message flow, then check his link from the docs.

How do I make my repositories async without affecting upper layers

I have an Asp.net MVC 5 application that has:
Web UI layer
Business Logic layer
Data repositories layer
They are also referenced in this order. UI only accesses business logic, and business logic references repositories.
As with 99% of applications everything can and should be executed synchronously except calls into database (or other I/O expensive operations). That's why I would like to make Data layer asynchronous but without affecting upper layers to make all upper calling methods async (all the way to controller actions).
Is that possible?
What I was thinking to do
I was thinking of changing things this way.
Data layer method
public async Task<SomeEntity> GetData()
{
return await Task.Run<SomeEntity>(() => ...);
}
Business logic method
public SomeEntity GetData()
{
return this.repo.GetData().Result;
}
Questions
Does this make sense and would I actually get my code to execute in asynchronous manner?
Update
After reading Stephen Cleary's blog post it made it more clear to me that whole call stack to the bottom (data layer that splits the synchronisity) is being split by the data async call hence all calls on the stack should be async and split as well.
If this thinking is correct then are my assumptions correct when I say that
In order to not have the whole synchronous call stack converted to async we should create a separate thread that would work asynchronously and our synchronous thread would use it.
Question 2
Is this assumption correct and if it is, is that the only way to keep some parts synchronous?
As with 99% of applications everything can and should be executed synchronously except calls into database.
Not at all. Anything that is I/O-based should be asynchronous.
So, the data layer does database I/O, and should be asynchronous.
The business logic layer uses the data layer, which is I/O-based, and should be asynchronous.
The UI layer uses the business logic layer, which is I/O-based, and should be asynchronous.
Of course, only those methods that are actually I/O-based should be made asynchronous; the rest should be synchronous. But I find that in data-access-heavy applications, they should be almost entirely asynchronous.
Does this make sense and would I actually get my code to execute in asynchronous manner?
No. Sorry, but you should never wrap asynchronous code in Task.Run and block on it in an ASP.NET application. All that does is use up more threads than necessary for processing your request. It would be better to keep it all synchronous than to use multiple threads to keep it synchronous.
On ASP.NET, you have to allow the asynchrony to propagate through all layers in order to have asynchronous actions/handlers (and all the benefits that come with it, namely, scalability).
Mixing sync with async in this manor can be dangerous as it invites deadlocks. Stephen Cleary explains this very well here:
http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html

Resources