Why all my requests are blocked until async/await method executed - asp.net

I have an asp.net mvc async method waiting for 10 second.
The problem is IIS Express (production IIS also) stops processing incoming requests until that async method finishes.
I thought await keyword frees current thread for new incoming request. But it seems that I missed something.
public async Task<ActionResult> AsyncMethod()
{
using (DeliveryPortalEntities context = new DeliveryPortalEntities())
{
await context.Database.ExecuteSqlCommandAsync("WAITFOR DELAY '00:00:10'");
}
return Json(new { status = "ok" });
}
Update! Can anyone explain why during this code execution IIS stops answer requests immediately.
public async Task<ActionResult> AsyncMethod()
{
await Task.Delay(10000).ConfigureAwait(false);
return new EmptyResult();
}

I thought await keyword frees current thread for new incoming request.
It does; the thread is free. However, the request is not complete. And if that request has a read/write lock on the session, then no other requests for that session can be processed until that lock is free.
To resolve this, you'll need to change your session usage. If you can go sessionless, that's best - it allows really good horizontal scalability. If not, try to go read-only. Long requests with a read-only session lock can run concurrently with other requests in that same session if they also only need a read-only session lock.

Related

502 bad gateway when async request hits 2 min

The issue described below doesn't happen on local development, only once I have deployed everything to test environment, which is hosted on Azure Web App.
When calling an API endpoint from Angular (where I use Observer and subscribe on the request), the request is processed and may sometimes take longer than 2 minutes to be processed. When the request hits 2 minutes, I instantly get a 502 bad gateway, while the async process continues until finished.
In the request processing I do a couple of remote powershell script executions, I made sure that both my powershell methods run asynchronously, and made sure that the API endpoint is async. In my angular frontend from where I do the request, I use observer and subscribe on the request being made.
My next step was wanting to make some sort of request that just starts the process, and then somehow be able to keep requesting until I get a response that the response has finished, to avoid the 502 error, but I don't know where or how to start, but I don't know if this approach could even work for sure.
Backend is set up using C#, .NET Core 2.2. Frontend is Angular (7?).
I want to get the expected response instead of hitting 502 Bad Gateway everytime processing hits 2 minutes.
Code:
First I call
this.objectService.processObjectsForMerge(request).subscribe(res => {});
Which, from the service, prepares following request
processObjectsForMerge(req: ProcessObjectsForMergeRequest): Observable<ProcessObjectsForMergeResponse>{
return this.http.post<ProcessObjectsForMergeResponse>(this.API_URL + '/Object/ProcessObjectsForMerge',req, {
headers: new HttpHeaders({
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + this.auth.getAccessToken()
})
});
}
And is received in the following endpoint
[HttpPost]
[Route("ProcessObjectsForMerge/")]
public async Task<IActionResult> ProcessObjectsForMerge([FromBody] ProcessMergeRequestModel request)
{
if (request == null || string.IsNullOrEmpty(request.VersionNumber) || string.IsNullOrEmpty(request.CuLevel)) return BadRequest("Failed to validate data");
var permissionGranted = DoesUserHavePermissionForRequest(request.ShortGuid);
if (!permissionGranted) return BadRequest();
var isSuccessful = await new ProcessObjectsForMergeService().Process(request);
var message = !isSuccessful ? "Failed to process objects for merge." : "Successfully processed the objects for merge.";
return Ok(new {message, log});
}
Update:
I have found a temporary solution, in web.config of the API I was able to increase the timeout time.
I feel this is bad practice though, so gonna implement a message queue (using rabbitMQ probably) to execute my initial idea on how to solve it and see if it works out the way I expect.

Request Flow in Asynchronous Controller Spring MVC

I was trying to understand Asynchronous Controller implementation from one of links:
http://shengwangi.blogspot.in/2015/09/asynchronous-spring-mvc-hello-world.html
I was puzzled on point that Controller thread received request and exists. Then service method received the request for further processing.
#RequestMapping("/helloAsync")
public Callable<String> sayHelloAsync() {
logger.info("Entering controller");
Callable<String> asyncTask = new Callable<String>() {
#Override
public String call() throws Exception {
return helloService.doSlowWork();
}
};
logger.info("Leaving controller");
return asyncTask;
}
Since, Controller exists it and pass the control to appropriate handler mapping/ jsp. What will be seen on the browser for the user ?
Browser waits for the response to process it.
Asynchronous process takes place only at the server end and it has nothing to do with the browser. Browser sends the request and waits for the server to write the response back.
Since you returned Callable doesnt mean that controller exists the flow. Spring`s response handlers will wait for async task to get executed to write the response back.
Please go through AsyncHandlerMethodReturnValueHandler which handles Asynchronous response returned from the controller.
if you return callable then it will be handled by CallableHandlerMethodReturnvaluehandler :
public void handleReturnValue(Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
if (returnValue == null) {
mavContainer.setRequestHandled(true);
return;
}
Callable<?> callable = (Callable<?>) returnValue;
WebAsyncUtils.getAsyncManager(webRequest).startCallableProcessing(callable, mavContainer);
}
I had cleared my doubt from this link:
https://dzone.com/articles/jax-rs-20-asynchronous-server-and-client
However, they used different way to accomplish the asynchronous processing but the core concept should be the same for every approach.
Some important part of the article:
The idea behind asynchronous processing model is to separate
connection accepting and request processing operations. Technically
speaking it means to allocate two different threads, one to accept the
client connection and the other to handle heavy and time consuming
operations. In this model, the container dispatched a thread to accept
client connection (acceptor), hand over the request to processing
(worker) thread and releases the acceptor one. The result is sent back
to the client by the worker thread. In this mechanism client’s
connection remains open. May not impact on performance so much, such
processing model impacts on server’s THROUGHPUT and SCALABILITY a lot.

AsyncTimeoutAttribute is not working with Controller Actions

We tried to use the following code to increase request timeout for our backup process which runs on IIS and ASP.NET MVC:
[AsyncTimeout(79200000)]
public async Task<ActionResult> DailyBackup(Guid secret)
{
HttpContext.Server.ScriptTimeout = 22*3600;
await Backups.Create();
return null;
}
However, this didn't change the timeout and after a short period of time, ASP.NET MVC returns us an empty page and await Backups.Create() is continue to run separately in background.
What should we do in order to increase timeout for certain actions without changing our Web.Config file?

Clarifying RxJava Observable Threading with Retrofit

At http://square.github.io/retrofit/ where it talks about asynchronous, there is a phrase "Observable requests are subscribed asynchronously and observed on the same thread that executed the HTTP request" where I wanted to clarify.
So in this case which thread that actually will execute the Http Request: Lets say main thread makes a call to Observable getUserPhoto(#Path("id") int id)? Will it be the main thread or thread that subscribe the request that execute the http request?
Regarding to the documentation, it will be the thread which execute the request.
If the result of your request change something in the view, you may need to observe (consume) your result in the main thread. In this case, add a call to the observeOn method before you subscribe to your observable.
The answer is yes, when you execute your method by using a service, using the observeOn method will create an "Observer" that will be waiting for an opportunity to execute the request once the mainThread has an opportunity to do so.
So first use .observeOn(AndroidSchedulers.mainThread()) to observe the main thread, and then subscribe the action or callback that will execute once you got a response from your remote API.
supposing you use this annotation in your API interface
#GET("/home")
Observable<Response> getHome();
this would be an example:
service.getHome().observeOn(AndroidSchedulers.mainThread()).subscribe(
new Action1<Response>() {
#Override
public void call(Response response) {
System.out.println("Response home");
System.out.println(response.getStatus());
System.out.println(response.getBody().mimeType());
System.out.println(response.getReason());
System.out.println(response.getUrl());
StringWriter w = new StringWriter();
try{
IOUtils.copy(response.getBody().in(),w,"UTF-8");
System.out.println(w.toString());
}catch (IOException e){}
}
});
For more information you may check this RxJava(the one that Retrofits uses of course) link where it states that it uses Android's Handler(which is a class for handling threads)
"It provides a Scheduler that schedules an Observable on a given Android Handler thread, particularly the main UI thread."

MVC 3 Async Controller for video conversion

I'm not really to up on Async controller, I'm currently reading what I can but I thought I'd try and save myself some time as I'm on a rather tight deadline.
I'm working on a project that allows users to upload video clips but I then want to convert them to different formats for playback on different devices. I was thinking of doing this straight after the upload has happened but the down side is the user will be waiting for that to finish before they can navigate away.
So to my question, would using a async controller and action allow the conversion process to happen with out the user having to wait at the upload page?
Apologies if this is a stupid question, like I said I've only just started reading about async controllers
Thanks
No. AsyncController frees up the thread executing the controller to do other things when there is low CPU usage (for example heavy I/O). A result will not be returned to the client until the action method returns.
You are better off starting your conversion in a separate thread, if you want to return a page quickly. We use this approach when sending emails, so that the user does not have to wait for the email to be sent before we return a view to them.
Here is how we send emails.
// this can go in an action method, or you can DI this code as a service
var sender = new SmtpEmailSender(message);
var thread = new Thread(sender.Send);
thread.Start();
...
return View(model);
// this is the code run by the new thread
// (EmailMessage is a custom type in our app)
public class SmtpEmailSender
{
public SmtpEmailSender(EmailMessage emailMessage)
{
// arg to instance field
}
public void Send()
{
// construct System.Net mail and send over SMTP
}
}

Resources