ServerResponse returns before execution of Mono - spring-webflux

I'm trying to validate the request body then based on it either return a bad request or proceed further. The issue is that the proceed flow is not executed. I'm attaching two solutions that I have tried:
Solution 1
public Mono<ServerResponse> startOrder(ServerRequest request) {
return request.bodyToMono(OrderDto.class)
.map(order -> Utils.validate(order))
.flatMap(listErrors -> {
if(listErrors.isEmpty()){
Mono<OrderResponse> orderResponseMono = this.service.startOrder(request.bodyToMono(OrderDto.class));
return ServerResponse.ok().body(orderResponseMono, OrderResponse.class);
}
Mono<OrderResponse> res = Mono.just(new OrderResponse(HttpStatus.BAD_REQUEST.value(), new ApiError(list.toString())));
return ServerResponse.badRequest().body(res, OrderResponse.class);
});
}
Solution 2
return request.bodyToMono(OrderDto.class)
.map(tt -> Utils.validate(tt))
.filter(res -> !res.isEmpty())
.map(r -> new OrderResponse(HttpStatus.BAD_REQUEST.value(), new ApiError("validation errors")))
.switchIfEmpty(this.service.initOrder(request.bodyToMono(OrderDto.class), HeaderValues.create(request.headers())))
.flatMap(res -> ServerResponse.badRequest().body(Mono.just(res), OrderResponse.class));
Validation method
public static List<String> validate(OrderDto request) {
List<String> result = new ArrayList<>();
if(request.getId == null){
result.add("Id should not be null");
}
if(request.getTitle() == null){
result.add("Title should not be null");
}
if(request.getDescription() == null){
result.add("Description should not be null");
}
return result;
}
When validation succeeds, the body with the result is returned but not when it fails.
What can cause the Mono to not be executed?

The issue you have is that you are trying to consume the response twice by calling response.bodyToMono(OrderDTO.class) two times in your code.
Once you have consumed the body from a response, the server will be able to close the connection to the called system.
If you call it multiple times it will (probably, not checked or verified) return a Mono.empty() which means it will not continue the flow as expected.
You should make it a habit of consuming the response body as quick as possible so that the server can close the connection to free up resources instead of passing around the response object.
Since we are working with streams, the connection will not be freed until the response is consumed.

Related

Efficient thread use on high traffic ASP.NET Core Web API with processing timeout

My ASP.NET Core Web API (Linux) endpoint needs to serve a high volume of concurrent requests. If the request takes more than 200ms then it should abort and return a custom piece of JSON. The code is all awaitable. The request must always return HTTP 200 and the HTTP request timeout cannot be reduced from 30 secs to 200ms.
What is the most efficient way to accomplish what I want? Should I use a Task? Should I use Task.Wait or Task.WaitAsync? Or should the work methods run in the HTTP request thread, periodically check Stopwatch.Elapsed and throw a timeout exception?
This is my current code:
var task = Task.Factory.StartNew(async () =>
{
// Processing part 1
var result1 = await DoWorkPart1("Param1");
if (cancellationToken.IsCancellationRequested())
cancellationToken.ThrowIfCancellationRequested();
// Processing part 2
var result2 = wait DoWorkPart2(result1);
return result2;
}).Unwrap(); // Return lambda task, not outer task
// Is it better to use WaitAsync?
task.Wait(TimeSpan.FromMilliseconds(150));
if (task.IsCompleted) // Result within timeout
{
if (task.Exception == null) // Success
{
return Ok(task.Result);
}
else
{
return Ok(new FailedObject() { Reason = ReasonEnum.UnexpectedError };
}
}
else // Timeout
{
return OK(new FailedObject() { Reason = ReasonEnum.TookTooLong };
}
What is the most efficient way to accomplish what I want?
I recommend using CancellationTokens to cancel. With a very short timeout like 200ms, you might just want to create a CancellationTokenSource with that timeout and ignore the CancellationToken provided to you by ASP.NET, which handles situations like clients disconnecting early.
Should I use a Task? Should I use Task.Wait or Task.WaitAsync? Or should the work methods run in the HTTP request thread, periodically check Stopwatch.Elapsed and throw a timeout exception?
I would say none of these. Instead, pass the CancellationToken down as far as you possibly can, ideally right to the lowest-level APIs your asynchronous code is calling.
If some of those APIs ignore their cancellation tokens, or if it's possible they may complete synchronously (e.g., due to caching), then adding cancellationToken.ThrowIfCancellationRequested(); in-between steps is a good idea.
Side note: Don't use StartNew.
using var cts = new CancellationTokenSource(TimeSpan.FromMilliseconds(200));
try
{
// Processing part 1
var result1 = await DoWorkPart1("Param1", cts.Token);
cts.Token.ThrowIfCancellationRequested();
// Processing part 2
var result2 = wait DoWorkPart2(result1, cts.Token);
return Ok(result2);
}
catch (OperationCanceledException)
{
return OK(new FailedObject() { Reason = ReasonEnum.TookTooLong };
}
catch
{
return Ok(new FailedObject() { Reason = ReasonEnum.UnexpectedError };
}

How to make several synchronuous call of rxjava Single

I have difficulties making sequential calls of RxJava Single observerable. What I mean is that I have a function that makes http request using retrofit that returns a Single.
fun loadFriends(): Single<List<Friend>> {
Log.d("msg" , "make http request")
return webService.getFriends()
}
and if I subscribe from several places at the same time:
loadFriends().subscribeOn(Schedulers.io()).subscribe()
loadFriends().subscribeOn(Schedulers.io()).subscribe()
I want that loadFriends() makes only one https request but in this case I have two http request
I know how to solve this problem in blocking way:
The solution is to make loadFriends() blocking.
private val lock = Object()
prival var inMemoryCache: List<Friends>? = null
fun loadFriends(): Single<List<Friend>> {
return Single.fromCallable {
if(inMemoryCache == null) {
synchronize(lock) {
if(inMemoryCache == null) {
inMemoryCache = webService.getFriends().blockingGet()
}
}
}
inMemoryCache
}
But I want to solve this problem in a reactive way
You can remedy this by creating one common source for all your consumers to subscribe to, and that source will have the cache() operator invoked against it. The effect of this operator is that the first subscriber's subscription will be delegated downstream (i.e. the network request will be invoked), and subsequent subscribers will see internally cached results produced as a result of that first subscription.
This might look something like this:
class Friends {
private val friendsSource by lazy { webService.getFriends().cache() }
fun someFunction() {
// 1st subscription - friends will be fetched from network
friendsSource
.subscribeOn(Schedulers.io())
.subscribe()
// 2nd subscription - friends will be fetched from internal cache
friendsSource
.subscribeOn(Schedulers.io())
.subscribe()
}
}
Note that the cache is indefinite, so if periodically refreshing the list of friends is important you'll need to come up with a way to do so.

How to call a private method from reactive subscribe of Mono and return a specific type in Spring 5?

I have a main method whose return type WebClient. In this method I get a Mono object and using subscribe I'm trying to call another method which returns webclient object. Now within subscribe, I have webclient object which I want to return. I'm blocked here as I'm not sure how to return the object and where to put the return keyword.
Main method:-
public WebClient getWebClientWithAuthorization(String t) {
-----
----
Mono<AccessToken> accessToken = authenticationProvider.getUserAccessToken(serviceConnectionDetails, queryParams);
Disposable disposable = accessToken.subscribe(
value -> getWebClientBuilder(t, value.getAccessToken()),
error -> error.printStackTrace(),
() -> System.out.println("completed without a value")
);
}
Below getWebClientBuilder method returns webclient object:-
private WebClient getWebClientBuilder(String tenantDomain, String accessToken) {
//TODO Logic for Saving the Token using Caching/Redis mechanism will be taken up from here and implemented in future Sprints
logger.info("Bearer token received: "+ CommerceConnectorConstants.REQUEST_HEADER_AUTHORIZATION_BEARER +" "+ accessToken);
if (null != proxyHost) {
return utilsbuilder.baseUrl(tenantDomain).filter(oauth2Credentials(accessToken)).clientConnector(getHttpConnector()).build();
} else {
return utilsbuilder
.baseUrl(tenantDomain)
.filter(oauth2Credentials(accessToken))
.build();
}
}
Now in getWebClientWithAuthorization method, where to put the return keyword inside subscribe or outside subscribe.
Think "Reactive" end to end
In my opinion, what is the most important when star building application using Reactive Programming is treating any call as asynchronous hence providing end to end asynchronous and non-blocking communication.
Thus, what I suggest you is providing instead of synchronous type a Mono<WebClient> in the following way:
public Mono<WebClient> getWebClientWithAuthorization(String t) {
-----
----
Mono<AccessToken> accessToken = authenticationProvider.getUserAccessToken(serviceConnectionDetails, queryParams);
return accessToken.map(value -> getWebClientBuilder(t, value.getAccessToken()))
.doOnError(error -> error.printStackTrace())
.doOnComplete(() -> System.out.println("completed without a value"))
);
}
So, now you may easily map value to the WebClient's instance and send it to the downstream. In turn, your downstream may react to that value and transform WebClient to the execution of HTTP call as it is shown in the following example:
getWebClientWithAuthorization("some magic string here")
.flatMapMany(webClient -> webClient.get()
.uri("some uri here")
.retrieve()
.bodyToFlux(MessageResponse.class))
// operate with downstream items somehow
// .map
// .filter
// .etc
// and return Mono or Flux again to just continue the flow
And remember, just continue the flow and everywhere specify reactive types if async communication is supposed. There is no sense to subscribe to the source until you met some network boundary or some logical end of the stream where you do not have to return something back.

How to make an Attended call transfer with UCMA

I'm struggling with making a call transfer in a UMCA IVR app I've built. This is not using Lync.
Essentially, I have an established call from an outside user and as part of the IVR application, they select an option to be transferred. This transfer is to a configured outside number (ie: Our Live Operator). What I want to do is transfer the original caller to the outside number, and if a valid transfer is established, I want to terminate the original call. If the transfer isn't established, I want to send control back to the IVR application to handle this gracefully.
My problem is my EndTransferCall doesn't get hit when the transfer is established. I would have expected it to hit, set my AutoResetEvent and return a True, and then in my application I can disconnect the original call. Can somebody tell me what I'm missing here?
_call is an established AudioVideoCall. My application calls the Transfer method
private AutoResetEvent _waitForTransferComplete = new AutoResetEvent(false);
public override bool Transfer(string number, int retries = 3)
{
var success = false;
var attempt = 0;
CallTransferOptions transferOptions = new CallTransferOptions(CallTransferType.Attended);
while ((attempt < retries) && (success == false))
{
try
{
attempt++;
_call.BeginTransfer(number, transferOptions, EndTransferCall, null);
// Wait for the transfer to complete
_waitForTransferComplete.WaitOne();
success = true;
}
catch (Exception)
{
//TODO: Log that the transfer failed
//TODO: Find out what exceptions get thrown and catch the specific ones
}
}
return success;
}
private void EndTransferCall(IAsyncResult ar)
{
try
{
_call.EndTransfer(ar);
}
catch (OperationFailureException opFailEx)
{
Console.WriteLine(opFailEx.ToString());
}
catch (RealTimeException realTimeEx)
{
Console.WriteLine(realTimeEx.ToString());
}
finally
{
_waitForTransferComplete.Set();
}
}
Is the behavior the same if you don't use the _waitForTransferComplete object? You shouldn't need it - it should be fine that the method ends, the event will still be raised. If you're forcing synchronous behavoir in order to fit in with the rest of the application though, try it like this:
_call.EndTransfer(
_call.BeginTransfer (number,transferOptions,null,null)
);
I'm just wondering if the waiting like that causes a problem if running on a single thread or something...

How to Force an Exception from a Task to be Observed in a Continuation Task?

I have a task to perform an HttpWebRequest using
Task<WebResponse>.Factory.FromAsync(req.BeginGetRespone, req.EndGetResponse)
which can obviously fail with a WebException. To the caller I want to return a Task<HttpResult> where HttpResult is a helper type to encapsulate the response (or not). In this case a 4xx or 5xx response is not an exception.
Therefore I've attached two continuations to the request task. One with TaskContinuationOptions OnlyOnRanToCompletion and the other with OnlyOnOnFaulted. And then wrapped the whole thing in a Task<HttpResult> to pick up the one result whichever continuation completes.
Each of the three child tasks (request plus two continuations) is created with the AttachedToParent option.
But when the caller waits on the returned outer task, an AggregateException is thrown is the request failed.
I want to, in the on faulted continuation, observe the WebException so the client code can just look at the result. Adding a Wait in the on fault continuation throws, but a try-catch around this doesn't help. Nor does looking at the Exception property (as section "Observing Exceptions By Using the Task.Exception Property" hints here).
I could install a UnobservedTaskException event handler to filter, but as the event offers no direct link to the faulted task this will likely interact outside this part of the application and is a case of a sledgehammer to crack a nut.
Given an instance of a faulted Task<T> is there any means of flagging it as "fault handled"?
Simplified code:
public static Task<HttpResult> Start(Uri url) {
var webReq = BuildHttpWebRequest(url);
var result = new HttpResult();
var taskOuter = Task<HttpResult>.Factory.StartNew(() => {
var tRequest = Task<WebResponse>.Factory.FromAsync(
webReq.BeginGetResponse,
webReq.EndGetResponse,
null, TaskCreationOptions.AttachedToParent);
var tError = tRequest.ContinueWith<HttpResult>(
t => HandleWebRequestError(t, result),
TaskContinuationOptions.AttachedToParent
|TaskContinuationOptions.OnlyOnFaulted);
var tSuccess = tRequest.ContinueWith<HttpResult>(
t => HandleWebRequestSuccess(t, result),
TaskContinuationOptions.AttachedToParent
|TaskContinuationOptions.OnlyOnRanToCompletion);
return result;
});
return taskOuter;
}
with:
private static HttpDownloaderResult HandleWebRequestError(
Task<WebResponse> respTask,
HttpResult result) {
Debug.Assert(respTask.Status == TaskStatus.Faulted);
Debug.Assert(respTask.Exception.InnerException is WebException);
// Try and observe the fault: Doesn't help.
try {
respTask.Wait();
} catch (AggregateException e) {
Log("HandleWebRequestError: waiting on antecedent task threw inner: "
+ e.InnerException.Message);
}
// ... populate result with details of the failure for the client ...
return result;
}
(HandleWebRequestSuccess will eventually spin off further tasks to get the content of the response...)
The client should be able to wait on the task and then look at its result, without it throwing due to a fault that is expected and already handled.
In the end I took the simplest route I could think of: hide the exception. This is possible because WebException has a property Response which gives access to the HttpWebResponse I want:
var requestTask = Task<WebResponse>.Factory.FromAsync(
webReq.BeginGetResponse,
ia => {
try {
return webReq.EndGetResponse(ia);
} catch (WebException exn) {
requestState.Log(...);
return exn.Response;
}
});
And then handle errors, redirects and success responses in the continuation task.