Is this fire and forget approach correct? - c#

I've implemented instagram api realtime updates. Basically they fire a POST request to a url I provide when there are new images added based on my subscription.
They said:
" you should acknowledge the POST within a 2 second timeout--if you need to do more processing of the received information, you can do so in an asynchronous task."
so I built something like:
[HttpPost]
[ActionName("realtime")]
public async Task<ActionResult> IndexPost()
{
var form = Request.Form;
Request.InputStream.Position = 0;
System.IO.StreamReader str = new System.IO.StreamReader(Request.InputStream);
string sBuf = str.ReadToEnd();
// deserialize this from json
var serializer = new JavaScriptSerializer();
var updates = serializer.Deserialize<IEnumerable<RealtimeUpdate>>(sBuf).ToList();
ProcessNewTaggedImages(updates);
return new ContentResult { Content = "Ok" };
}
where ProcessNewTaggedImages is running async.
public async void ProcessNewTaggedImages(List<RealtimeUpdate> updates)
{
Task.Run(() =>
{
// query Instagram api for new images
}
}
so basically when Instagram POSTs to www.mysite.com/realtime it does not wait for ProcessNewTaggedImages.
I just wanted to make sure this approach is correct for fire and forget approach because under Task.Run I receive a warning saying:
Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the await operator to the result of the call.
but I don't want await here because
the result of my processing does not matter for instagram call
timeout for POST is 2 seconds so I don't want to wait for this processing.
Can you confirm I am on the right track?
Ps: POST is working fine and all works good just wanted to confirm I've not done any mystake because I am mostly beginner to this async approach in C#.

If you need fire and forget functionality you don't need to add async keywords to your methods as your are not doing any awaits. So remove the async keywords from your code and the compiler will not complain about your code.

I think you might need to read though this first.
And I quote: "If an async method doesn’t use an await operator to mark a suspension point, the method executes as a synchronous method does, despite the async modifier."

Related

Wrapping both cpu-bound/io-bound long-running code into (async) Task

Consider the simple MVC5 controller:
public class DocumentsController {
// ctor code is omitted
[HttpPost, Route("api/documents/request/stamp={stamp}")]
public ActionResult RequestDocuments(string stamp) {
var documents = this.DocumentsRequestService.RequestByStamp(stamp);
return new JsonResult(documents);
}
}
The DocumentsRequestService does these things internally:
it sends a request to a dedicated MSMQ-queue (let's call it M) AND synchronously waits for an incoming message at the M's response queue:
using(var requestMessage = new Message()) {
requestMessage.Body = documentStamp;
requestMessage.Recoverable = true;
requestMessage.Label = "request";
requestMessage.ResponseQueue = this.requestedDocumentsResponseQueue;
requestMessage.Formatter = new XmlMessageFormatter(new Type[] { typeof(String) });
// send request
this.requestedDocumentsQueue.Send(requestMessage);
// synchronously wait for response
var responseMessage = this.requestedDocumentsResponseQueue.Receive();
if(responseMessage.Label.EndsWith("success")) {
return new DocumentsRequestResult(
success: true,
matches: parseMatchesList(responseMessage)
);
}
return new DocumentsRequestResult(
success: false,
matches: Enumerable.Empty<DocumentsRequestMatch>()
);
}
the consumer (Windows Service) of that message makes a specific api call. By saying 'specific' I mean that we use a third-party means to do that. This call is synchronous and quite long. When the processing ends the consumer sends a response message to the requesting message's response queue.
when response arrives at the M's response queue it's a time to parse and return the results to the controller.
From the end user's perspective this task should be blocking, or at least it should look like blocking.
As far as I understand running a Task makes use of parallelization. Whereas using the async-await pair makes the running task asynchronous. It could be helpful if several tasks would run in parallel.
Is it reasonable/possible to incorporate with Tasking/Asynchrony in my case? If yes, then where do I start?
The "asynchrony" of a network call is transparent to the caller. It doesn't matter to the caller whether the implementation is synchronous or asynchronous. Put another way, from a client's perspective, it's always asynchronous.
For example, the HTTP client couldn't care less if RequestDocuments is synchronous or asynchronous; either way, the HTTP client will send a request and receive a response some time later (i.e., asynchronously).
Similarly, the HTTP web server doesn't care whether the Win32 service is implemented synchronously or asynchronously. It just knows that it puts a message on a queue and some time later (i.e., asynchronously) it gets a response message from the queue.
As far as I understand running a Task makes use of parallelization. Whereas using the async-await pair makes the running task asynchronous.
Sort of. Task can be used for either asynchronous or parallel code, a fact that has caused much confusion. However, Task Parallel Library constructs such as Parallel and PLINQ are firmly in the parallel (non-asynchronous) world.
It could be helpful if several tasks would run in parallel.
I believe "concurrently" is the appropriate term here.
First, note that ASP.NET gives you a considerable amount of concurrency for free. If you want to make each request internally concurrent, then you can do so fairly easily via Task.WhenAll. For example, you can change your DocumentsRequestService call to be asynchronous (assuming your message queue API supports async calls):
using(var requestMessage = new Message()) {
...
// send request
await this.requestedDocumentsQueue.SendAsync(requestMessage);
// asynchronously wait for response
var responseMessage = await this.requestedDocumentsResponseQueue.ReceiveAsync();
...
}
Then you can call it multiple times simultaneously from a single controller action as such:
public async Task<ActionResult> RequestDocuments(string stamp1, string stamp2) {
var task1 = this.DocumentsRequestService.RequestByStampAsync(stamp1);
var task2 = this.DocumentsRequestService.RequestByStampAsync(stamp2);
var documents = await Task.WhenAll(task1, task2);
return new JsonResult(documents);
}

About ASP.NET Web API - Async and Await

I have the following Asynchronous method inside my AsyncController:
public async Task<Dashboard> GetFeeds()
{
var movies = new HttpClient().GetStringAsync("http://netflix/api/MyMovies");
var tweets = new HttpClient().GetStringAsync("http://twitter/api/MyTweets");
await Task.WhenAll(movies, tweets);
Dashboard dash = new Dashboard();
dash.Movies = Deserialize<Movies >(movies.Result);
dash.Tweets = Deserialize<Tweets >(tweets.Result);
return dash;
}
In this method do different call APIs, one with different return time from each other. What I can not understand about Task<> is because I have to wait for the return of the two to update my client? Being that I'm creating new threads.
Imagining that I play the return of each API in a PartialView, the result I thought would get:
-First I would have my Movies list (it only takes 5s), -> Show for my user
-And Then would my list of Tweets -> Show for my user
But what I see is:
-While The Twitter request does not end I did not get to play the data I got from Netflix on-screen for my user.
The big question is: A Task<> serves only for the processing to be done faster?
I can not play the information on the screen according to the turnaround time of each API that I ordered?
This is the call to my method
public async Task<ActionResult> Index()
{
var feeds = await GetFeeds();
return View(feeds);
}
I confess, I'm very confused, or, maybe you did not understand the concept of Task<>.
The way ASP.NET MVC works is that a single controller action handles a single HTTP request, and produces a single HTTP response. This is true whether the action is synchronous or asynchronous.
In other words (as I explain on my blog), async doesn't change the HTTP protocol. To return an "initial result" to the client browser and update the page (or part of the page) with other data, you'll need to use a technology designed for that: AJAX, or SignalR.
For more information, see the "Asynchronous Code Is Not a Silver Bullet" section of my MSDN article on async ASP.NET.

How to make an async call not prevent action from returning response to user

I have the following async code
public async static void SendAsync(string url)
{
try
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.KeepAlive = false;
request.Timeout = 5000;
var response = await request.GetResponseAsync().ConfigureAwait(false);
response.Close();
}
catch (Exception ex)
{
SendException(ex, url);
}
}
Which is called by the controller action.
public ActionResult Details(string id)
{
// DO something
SendAsync(some-valid-url);
// Do something
return View();
}
When i debug it - it runs async and hits
return View();
and exits before it is comes to
response.Close();
But in fiddler you can see that the http response is not sent by the browser and it waits for the SendAsync function to finish processing, which is not what i want. I want the http response to return back to the user right away.
What do I have to change here to achieve that?
i actually edited it and am now doing async static void since i do not
need to track the end of the task,
But you do need to keep track, as MVC will close the connection when Details returns, you need to tell MVC you are waiting for a background action.
public async Task<ActionResult> DetailsAsync(string id)
{
// DO something
var sendTask = SendAsync(some-valid-url);
// Do something else that does not depend on sendTask
await sendTask;
return View();
}
To answer your updated comment
doing an await will make it wait for the async http call to finish.
Which i do not want.
To get the behavior you are looking for you need to use AJAX, the async/await system will not give you what you want by itself. (I have never really done MVC with AJAX so I don't have a example for you how to do it)
doing an await will make it wait for the async http call to finish.
Which i do not want.
It sounds to me like you want fire and forget since you don't want to wait for the response.
There are a few negative points to bare in mind (such as no error handling, no guarantees, etc), so I would recommend reading into this a bit before dropping it into your project.
This is, in my opinion, is the easiest way to call a method with fire and forget.
ThreadPool.QueueUserWorkItem(o => SendAsync(some-valid-url));
This will request an available thread from the app pool. It will then use that thread to execute the method without blocking your current running one.
I hope this helps.

Return HTTP Response immediately in ASP.NET Web API

I am working on a WebAPI2 project doing some data collection, and I am trying to figure out how I can reduce the response time of my API methods.
I have a JavaScript function that posts information to my api. My API receives this information, inserts it in to the database, and then returns an HTTP Accepted.
Lets say there is a 5 second wait time for the data processing to be completed
// POST api/<controller>
public HttpResponseMessage Post([FromBody]string value)
{
//This represents 5000 milliseconds of work
System.Threading.Thread.Sleep(5000);
return new HttpResponseMessage(HttpStatusCode.Accepted);
}
This means, when my JavaScript function calls the Post Method, it waits 5 seconds for the response.
Is there a way I can immediately return a response of HTTP Accepted, and then continue processing my data?
Update solution from lilo.jacob
Ok, I've updated my method with the threading solution found below. Here is the new code
// POST api/<controller>
public HttpResponseMessage Post([FromBody]string value)
{
new System.Threading.Tasks.Task(() =>
{
//This represents 5000 milliseconds of work
System.Threading.Thread.Sleep(5000);
}).Start();
return new HttpResponseMessage(HttpStatusCode.Accepted);
}
The response is returned almost immediately, which is exactly what I was looking for.
Here are some results from Fiddler showing the change in response time
The first response show the lag with WebAPI on startup, requests 4,5, and 7, are using threading and fired immediately after each other. Response 11 shows the same request without threading enabled, notice the 5 second delay.
Very cool, clean, and lean solution to the problem.
You can try execute your "expensive" code in separate thread.
It will be something like this:
// POST api/<controller>
public HttpResponseMessage Post([FromBody]string value)
{
new System.Threading.Tasks.Task(() =>
{
//insert to db code;
}).Start();
return new HttpResponseMessage(HttpStatusCode.OK);
}
I believe #lilo,jacob's answer is not a reliable solution if the background task takes long-time. It may never complete and you lost data. Read this answer please:
https://stackoverflow.com/a/25275835/538387

Web Api + HttpClient: An asynchronous module or handler completed while an asynchronous operation was still pending

I'm writing an application that proxies some HTTP requests using the ASP.NET Web API and I am struggling to identify the source of an intermittent error.
It seems like a race condition... but I'm not entirely sure.
Before I go into detail here is the general communication flow of the application:
Client makes a HTTP request to Proxy 1.
Proxy 1 relays the contents of the HTTP request to Proxy 2
Proxy 2 relays the contents of the HTTP request to the Target Web Application
Target Web App responds to the HTTP request and the response is streamed (chunked transfer) to Proxy 2
Proxy 2 returns the response to Proxy 1 which in turn responds to the original calling Client.
The Proxy applications are written in ASP.NET Web API RTM using .NET 4.5.
The code to perform the relay looks like so:
//Controller entry point.
public HttpResponseMessage Post()
{
using (var client = new HttpClient())
{
var request = BuildRelayHttpRequest(this.Request);
//HttpCompletionOption.ResponseHeadersRead - so that I can start streaming the response as soon
//As it begins to filter in.
var relayResult = client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead).Result;
var returnMessage = BuildResponse(relayResult);
return returnMessage;
}
}
private static HttpRequestMessage BuildRelayHttpRequest(HttpRequestMessage incomingRequest)
{
var requestUri = BuildRequestUri();
var relayRequest = new HttpRequestMessage(incomingRequest.Method, requestUri);
if (incomingRequest.Method != HttpMethod.Get && incomingRequest.Content != null)
{
relayRequest.Content = incomingRequest.Content;
}
//Copies all safe HTTP headers (mainly content) to the relay request
CopyHeaders(relayRequest, incomingRequest);
return relayRequest;
}
private static HttpRequestMessage BuildResponse(HttpResponseMessage responseMessage)
{
var returnMessage = Request.CreateResponse(responseMessage.StatusCode);
returnMessage.ReasonPhrase = responseMessage.ReasonPhrase;
returnMessage.Content = CopyContentStream(responseMessage);
//Copies all safe HTTP headers (mainly content) to the response
CopyHeaders(returnMessage, responseMessage);
}
private static PushStreamContent CopyContentStream(HttpResponseMessage sourceContent)
{
var content = new PushStreamContent(async (stream, context, transport) =>
await sourceContent.Content.ReadAsStreamAsync()
.ContinueWith(t1 => t1.Result.CopyToAsync(stream)
.ContinueWith(t2 => stream.Dispose())));
return content;
}
The error that occurs intermittently is:
An asynchronous module or handler completed while an asynchronous operation was still pending.
This error usually occurs on the first few requests to the proxy applications after which the error is not seen again.
Visual Studio never catches the Exception when thrown.
But the error can be caught in the Global.asax Application_Error event.
Unfortunately the Exception has no Stack Trace.
The proxy applications are hosted in Azure Web Roles.
Any help identifying the culprit would be appreciated.
Your problem is a subtle one: the async lambda you're passing to PushStreamContent is being interpreted as an async void (because the PushStreamContent constructor only takes Actions as parameters). So there's a race condition between your module/handler completing and the completion of that async void lambda.
PostStreamContent detects the stream closing and treats that as the end of its Task (completing the module/handler), so you just need to be sure there's no async void methods that could still run after the stream is closed. async Task methods are OK, so this should fix it:
private static PushStreamContent CopyContentStream(HttpResponseMessage sourceContent)
{
Func<Stream, Task> copyStreamAsync = async stream =>
{
using (stream)
using (var sourceStream = await sourceContent.Content.ReadAsStreamAsync())
{
await sourceStream.CopyToAsync(stream);
}
};
var content = new PushStreamContent(stream => { var _ = copyStreamAsync(stream); });
return content;
}
If you want your proxies to scale a bit better, I also recommend getting rid of all the Result calls:
//Controller entry point.
public async Task<HttpResponseMessage> PostAsync()
{
using (var client = new HttpClient())
{
var request = BuildRelayHttpRequest(this.Request);
//HttpCompletionOption.ResponseHeadersRead - so that I can start streaming the response as soon
//As it begins to filter in.
var relayResult = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
var returnMessage = BuildResponse(relayResult);
return returnMessage;
}
}
Your former code would block one thread for each request (until the headers are received); by using async all the way up to your controller level, you won't block a thread during that time.
I would like to add some wisdom for anyone else who landed here with the same error, but all of your code seems fine. Look for any lambda expressions passed into functions across the call-tree from where this occurs.
I was getting this error on a JavaScript JSON call to an MVC 5.x controller action. Everything I was doing up and down the stack was defined async Task and called using await.
However, using Visual Studio's "Set next statement" feature I systematically skipped over lines to determine which one caused it. I kept drilling down into local methods until I got to a call into an external NuGet package. The called method took an Action as a parameter and the lambda expression passed in for this Action was preceded by the async keyword. As Stephen Cleary points out above in his answer, this is treated as an async void, which MVC does not like. Luckily said package had *Async versions of the same methods. Switching to using those, along with some downstream calls to the same package fixed the problem.
I realize this is not a novel solution to the problem, but I passed over this thread a few times in my searches trying to resolve the issue because I thought I didn't have any async void or async <Action> calls, and I wanted to help someone else avoid that.
A slightly simpler model is that you can actually just use the HttpContents directly and pass them around inside the relay. I just uploaded a sample illustrating how you can rely both requests and responses asynchronously and without buffering the content in a relatively simple manner:
http://aspnet.codeplex.com/SourceControl/changeset/view/7ce67a547fd0#Samples/WebApi/RelaySample/ReadMe.txt
It is also beneficial to reuse the same HttpClient instance as this allows you to reuse connections where appropriate.

Categories