I have a WebSocket that sends me events rapidly whenever there is a new message available, the event call for this looks like this:
Task.Factory.StartNew(() => _onStringMessage(e.RawData));
public async void _onStringMessage(var eventSent)
{
... // business logic
var variable = await _httpClient.getAsync(eventSent.Url);
... // business logic
var success = await _httpClient.postAsync(eventSent.Url + "/arg");
... // business logic
}
This code runs fine for a few iterations and then get a "Task was cancelled" exception error on either the GET or the POST request. The _httpClient is a standard .NET HttpClient wrapped in a IHttpClient class declared as a class variable. However, if I add a Semiphore like below, everything runs perfect:
public async void _onStringMessage(var eventSent)
{
await semiphore.WaitAsync();
... // business logic
var variable = await _httpClient.getAsync(eventSent.Url);
... // business logic
var success = await _httpClient.postAsync(eventSent.Url + "/arg");
... // business logic
semiphore.Release();
}
I am using .NET 4.6.1 and as far as I understood, both of these HTTP methods should be thread safe. Both methods ends up in a SendAsync method via the HTTP handler but that should also be thread safe. So I do not understand why I get the Task was cancelled exception? The only thing I can think of is that the server rejects the calls because too many requests at the same time, but then I imagine I would get some other error, like HTTP BadRequest or similar. This method runs approximately 10-20 times per second. My timeout is set to 1 second and all request are so far only on localhost.
Related
In my application I have a server which provides a REST-Api where my UI can communicate with.
Now I have to start a long running Process on the Server but I want the client not to wait for the response of the server.
I know I could just fire and forget the Post-Call and not await the response but I need to know at the client that the Process on the server was startet correctly.
So I thought about the following:
[HttpPost]
[Route("startscan")]
public HttpResponseMessage StartScan()
{
Task.Factory.StartNew( () =>
{
//Do long running things here
});
return Request.CreateResponse(HttpStatusCode.OK);
}
So my question now is: Will the task I started be executed to it's end? Background of the question is, that as far as I knwo a controller-instance is created for each call to it. So will the instance of the controller be terminated when the requested finished or will the Task I started run to it's end. The task can take up to 10 minutes or longer sometimes.
A simple approach would be to just use an asynchronous method without awaiting the Task result like so:
[HttpPost]
[Route("startscan")]
public async HttpResponseMessage StartScan()
{
DoLongRunningThings();
return Request.CreateResponse(HttpStatusCode.OK);
}
public async Task DoLongRunningThings()
{
// Do Stuff here
}
However, if you Processing is more complex and requires more resilience you should look into how to use background jobs. Here is a good collection of what you can use: https://stackoverflow.com/a/36098218/16154479
Will the task I started be executed to it's end?
Probably yes, but also possibly no. Sometimes it won't be executed completely. This is the result of misusing an ASP.NET app (which handles HTTP requests) as a background service (which runs outside of a request context).
There is a best practice that avoids possibly-partial execution: a distributed architecture (as I describe on my blog). The idea is that your controller enqueues a message describing the work to be done into a durable queue and then returns. Then there's a separate background service that reads from the queue and does the actual work.
We have a web application which consists of a Web API consumed by our UI. The web application is installed on different servers (tests before installing it by our clients).
On one server, we get a deadlock by the following endpoint:
[HttpGet, Route(Order = 1)]
public IHttpActionResult GetUserDetails(long userKey)
{
var userService = ResolveService<IUserService>();
var nameService = ResolveService<INameService >();
LoggInfo("Start userService.Get()"); //logged in logs
var result = userService.Get(userKey);
this.LoggInfo($"End userService.Get() with id = "{result.Id}); // logged in logs
try
{
LoggInfo($"Start nameService.Get()"); // logged in logs
result.Name = nameService.Get(result.Namekey).Result?.Name;
LoggInfo($"End nameService.Get()"); // not logged in logs
}
catch(Exception ex)
{
LogError("An error occured in NameService"); // not logged in logs
}
return Ok(result);
}
nameService.Get(id) is an async method :
public async Task<NameDTO> GetAsync(long key)
{
LogInfo("start NameService.Get()"); // not logged in logs
var query = GetQuery();
var name = await query.Select(MapName())
.FirstOrDefaultAsync(n => n.Key == key);
return name;
}
When I remove the async signature everything is working as expected, according to this article it is normal to have a deadlock.
Could you please explain me why this works in the other servers ?
Thanks in advance for your help
Could you please explain me why this works in the other servers?
In order for the deadlock to occur, there are three necessary parts:
A one-thread-at-a-time context, which all servers would have (the pre-Core ASP.NET context).
An await (without ConfigureAwait(false)) that acts asynchronously.
Code elsewhere that blocks a thread inside that context, waiting for the async method to finish. All servers also have this.
Most likely, the difference in behavior is due to the second part: an await that acts asynchronously. await first examines its awaitable (e.g., the Task passed to it), and if that awaitable is complete, then it continues executing the async method synchronously.
Specifically, this would happen if the Task<NameDTO> returned from GetAsync completed before the calling code hit the .Result. This would have to be extremely fast, but it's possible depending on caching, how fast your network hop is, how much the code is slowed down by load/neighbors/anti-virus, etc.
Recently I can across a code that we are using and is working fine and for the life of me I cannot figure out why.
We have a web API hosted in a service fabric cluster that is hosted over OwinCommunicationListener.
[HttpPost]
public async Task<HttpResponseMessage> WebApiMethod(RequestObject request)
{
string test;
SomeObject obj;
....
DoSomethingAsync(test, obj);
return this.ActionContext.CreateResponse(HttpStatusCode.OK, new { Status = "Success" });
}
private async Task DoSomethingAsync(string param1, SomeObject param2)
{
.....
await SomeOtherAsyncMethod();
.....
}
As far as I understand it should be a race condition between the method completion of DoSomethingAsync and the request disposing off and should throw an TaskCancelledException or something if later completes early, but it never does.
I am expecting some error since the task DoSomething is not awaited and yet it completes its work everytime. If I add
await Task.Delay(10000);
then the API response almost instantaneously and after the 10 seconds rest of the code is executed. Shouldn't by that time the host thread should be disposed since the original call was a Fire-and-Forget (not awaited).
What am I missing here.
There is nothing that ties request object with DoSomethingAsync. But even if you pass RequestObj reference right into DoSomethingAsync, the method will get completed with no problem as GC won't collect your RequestObj while you're referencing the object. Also, once async execution kicks off, it lives its own life meaning the callback might be completed on a different thread but the one that request-handling pipeline has been dispatched with.
Given:
A legacy non-async API method on an ASP.NET/WCF web service
New async internal library
New async Web API controller that should be used going forward
A "storage provider" object that only has an async interface. Its tests pass when run asynchronously, and when run synchronously outside a request context.
The option "go async all the way" is not on the table, since it would break backward compatibility.
public class Impl {
// This works fine when used asynchronously
public Task<Guid> SaveThingAsync(Thing thingToSave) {
return await _storageProvider.saveAsync(thingToSave);
}
public Guid SaveThing(Thing thingToSave) {
// "Obviously", this code creates a deadlock when called
// from within the request context
// return SaveThingAsync(thingToSave).Result
// Not so obviously, this also creates a deadlock
// return SaveThingAsync(thingToSave)
// .ConfigureAwait(false)
// .GetAwaiter()
// .GetResult()
// This was deadlocking, but magically stopped
// return Task.Run(
// async () => await SaveThingAsync(thingToSave)
// .ConfigureAwait(false)
// ).Result;
// This one works
var saveTask = Task.Run(async () =>
await SaveThingAsync(thingToSave)));
var result = saveTask.ConfigureAwait(false).GetAwaiter().GetResult();
return result;
}
Why?
Task.Run steps "outside" the request context - it just runs on the thread pool context. So, it won't deadlock because SaveThingAsync doesn't resume on the request context.
On a side note, the ConfigureAwait(false) is meaningless there, since there is no await to configure.
On another side note, "async all the way" should still be an option. WebAPI and WCF clients don't care whether the implementation they're calling is synchronous or asynchronous. Changing a WCF method implemented synchronously to a WCF method implemented asynchronously is invisible to client code.
I am writing an ASP.NET MVC 5 application which among others uses web services to get/process some the data.
The data flow of the app is following: MVC Action -> Service B -> ExtSvc which is async wrapper of a web service
Here are some examples:
public class ExtSvc
{
//Convert Event based async pattern to task based async pattern:
private Task<Response> ProcessExtRequestAsync(Request request)
{
TaskCompletionSource<Response> taskCompletionSource =
AsyncServiceClientHelpers.CreateSource<Response>(request);
ProcessRequestCompletedEventHandler handler = null;
handler =
(sender, e) =>
AsyncServiceClientHelpers.TransferCompletion(
taskCompletionSource,
e,
() => e.Result,
() => this.Service.ProcessRequestCompleted -= handler);
this.Service.ProcessRequestCompleted += handler;
try
{
this.Service.ProcessRequestAsync(request, taskCompletionSource);
}
catch (Exception)
{
this.Service.ProcessRequestCompleted -= handler;
taskCompletionSource.TrySetCanceled();
throw;
}
return taskCompletionSource.Task;
}
//Usage:
public async Task<Response> UpdateRequest(some arguments)
{
//Validate arguments and create a Request object
var response = await this.ProcessExtRequestAsync(request)
.ConfigureAwait(false);
return response;
}
}
Class B is the one that uses ExtSvc in a synchronous way
public class B
{
public ExtSvc service {get; set;}
public Response Update(arguments)
{
//some logic
var result = this.ExtSvc.UpdateRequest(arguments).Result;
//some logic
return result
}
}
Finally the MVC action (also synchronous)
public ActionResult GetResponse(int id)
{
//some logic
B.Update(id);
//some logic
return View(...);
}
The described flow throws an error
A first chance exception of type 'System.InvalidOperationException'
occurred in System.Web.dll
Additional information: An asynchronous operation cannot be started at
this time. Asynchronous operations may only be started within an
asynchronous handler or module or during certain events in the Page
lifecycle. If this exception occurred while executing a Page, ensure
that the Page is marked <%# Page Async="true" %>. This exception may
also indicate an attempt to call an "async void" method, which is
generally unsupported within ASP.NET request processing. Instead, the
asynchronous method should return a Task, and the caller should await
it.
on the following line of ExtSvc : this.Service.ProcessRequestAsync(request, taskCompletionSource); ProcessRequestAsync is a void method
So it corresponds to:
This exception may
also indicate an attempt to call an "async void" method, which is
generally unsupported within ASP.NET request processing
I know that converting GetResponse MVC action to asynchronous (by using async/await) and also converting the B class that actually uses ExtSvc to be asynchronous resolves the issue.
BUT my questions is:
If I can't change the signature of B class (because of an interface it implements) to return Task<Response> instead of Response it basically means that I can't use async/await on it so how this issue could be resolved?
ProcessRequestAsync is void but it's not async void. It looks like it's an EBAP API. EBAP components generally use AsyncOperationManager/AsyncOperation, which in turn do use SynchronizationContext to notify the underlying platform of the asynchronous operation (the last link is to my MSDN article on SynchronizationContext).
The exception you're seeing is because ASP.NET sees that notification (of the asynchronous operation starting) and says "whoa, there, fella. You're a synchronous handler! No async for you!"
Hands-down, the best approach is to make all methods asynchronous that should be asynchronous. This means B.Update should be B.UpdateAsync. OK, so there's an interface IB.Update - just change the interface to IB.UpdateAsync too. Then you're async all the way, and the code is clean.
Otherwise, you'll have to consider hacks. You could use Task.Run as #neleus suggested - that's a way of avoiding the ASP.NET SynchronizationContext so it doesn't "see" the asynchronous operation starting - but note that "ambient context" such as HttpContext.Current and page culture is lost. Or, you could (temporarily) install a new SynchronizationContext() onto the request thread - which also avoids the ASP.NET SynchronizationContext while staying on the same thread - but some ASP.NET calls assume the presence of the ASP.NET SynchronizationContext and will fail.
There's another hack you could try; it might work but I've never done it. Just make your handler return a Task<ActionResult> and use Task.FromResult to return the view: return Task.FromResult<ActionResult>(View(...)); This hack will tell ASP.NET that your handler is asynchronous (even though it's not).
Of course, all of these hacks have the primary disadvantage that you're doing sync-over-async (this.ExtSvc.UpdateRequest(arguments).Result), which means you'll be using one extra unnecessary thread for the duration of each request (or two threads, if you use the Task.Run hack). So you will be missing all the benefits of using asynchronous handlers in the first place - namely, scalability.
I think the error occurs because your code
this.Service.ProcessRequestAsync(request, taskCompletionSource);
actually calls SynchronizationContext's OperationStarted method that results in error as described here.
As a possible solution you can call your action on ThreadPoolSynchronizationContext
public async Task<ActionResult> GetResponse(int id)
{
//some logic
await Task.Run(() => { B.Update(id); });
//some logic
return View(...);
}
but it adds some overhead of utilizing a thread from the pool.