Handling HTTPClient performing multiple requests in fire and forget - c#

I have to make multiple Http post requests (few hundreds or can be more) and not wait for any of the responses as have an SLA. Without waiting for those response I need to send back response from my Web API (before performing mentioned multiple HTTP requests, I fetch data from another API and need to return back).
I have looked around and found "fire and forget" implementation which does not wait for response. I am not sure if this right way to do and since im returning without waiting for parallel fire and forget requests, how will HttpClient get disposed?
HttpClient client = new HttpClient();
var CompositeResponse = client.GetAsync(_SOMEURL);
List<MEDLogresp> sortedmeds = MEDLogresps.OrderBy(x => x.rxId).ThenBy(y => y.recordActionType);
Task.Run(() => Parallel.ForEach(sortedmeds, ele => clientMED.PostAsync(URL , new StringContent(JsonConvert.SerializeObject(ele), Encoding.UTF8, "application/json"))));
return ResponseMessage(Request.CreateResponse<CompositeResponse>(HttpStatusCode.OK, compositeResponse));

since im returning without waiting for parallel fire and forget
requests, how will httpclient get disposed?
You can use a single, shared static instance of HttpClient for the lifetime of your application and never Dispose() it. It is safe to use the same HttpClient from multiple threads concurrently.

Related

Is it possible for HTTP server to receive requests out of order even if they are sent sequentially?

(This discussion might not be specific to C#...)
I have a C# method SendMultipleRequests that sends HTTP POST request 10 times sequentially.
Is it possible for the server to receive requests out of order?
If my understanding is correct if the requests are sent concurrently (without await), the server could receive requests out of order, but in the example below it needs to wait for the response to be received at the client before sending next request, so the server will receive requests in order.
public async Task SendRequest(int i)
{
// definition of endpoint is omitted in this example
var content = new StringContent($"I am {i}-th request");
await HttpClient.PostAsync(endpoint, content);
}
public async Task SendMultipleRequests()
{
for (int i = 0; i < 10; i++)
{
await SendRequest(i);
}
}
with await your app will wait for the task returned by PostAsync to finish before it issues the next request - see the docs for postasync where it says “This operation will not block. The returned Task<TResult> object will complete after the whole response (including content) is read.” - using await will mean that you will only issue the next request after you I’ve read the content of the previous response
If you remove the await then your code will queue up ten tasks and start working on them all in some undefined order. The server will see requests in an unspecified order. This may be further exacerbated by the fact that the requests may take different routes through the internet, some slower. If you remove the await then you should capture the returned task into a list, then you can use something like await Task.WhenAll(list) to wait for them all to complete (unless you really want to fire and forget in which case you can assign them to the discard _ = client.PostAsync... but keeping the task allows you to discover and deal with exceptions that arose)

Is HttpClient async safe?

I suddenly got some doubts on this. HttpClient is thread safe according to MSDN (for GetAsync or PostAsync at least).
But if I do this
List<Task> tasks= new List<Task>();
tasks.Add(_httpClient.PostAsync(url1, requestMessage1));
tasks.Add(_httpClient.PostAsync(url2, requestMessage2));
Tasks.Wait(tasks);
Will I get correct results back all the time as both calls come from the same thread now?
Will I get correct results back all the time as both calls come from the same thread now?
Yes. That's the indented usage of HttpClient.
"An HttpClient instance is a collection of settings applied to all requests executed by that instance. In addition, every HttpClient instance uses its own connection pool"
HttpClient Class

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);
}

Sending multiple requests in any order but no more that 1 request/second

In my c# wpf application when a user presses a button I need to send to a server 10-20 requests. They can be sent in an arbitrary order but there has to be at least 10 of them because the server returns the results paginated.
Each client (my c# is a client) has an apy key and server can only handle 1 request per second per a certain client, otherwise the server returns an error.
How can send those requests properly? Should I necessarily use async and await? And can I send them in parallel and how? Doesn't async in this case means that they'll be sent in parallel?
And, how can I ensure that only 1 request per second is sent? I gathered it's not good to mix the threads, which is Thread.Sleep(1000) for my case, and async/await.
So, you could create a bunch of tasks that stagger the job by a second each time.
Something like:
List<Uri> uris=new List<Uri>(); //fill with uris
var tasks = uris.Select(async (u, i)=>{
await Task.Delay(TimeSpan.FromSeconds(i));
using(var wc = new WebClient())
{
return await wc.DownloadStringTaskAsync(u);
}
});
var results = await Task.WhenAll(tasks);

Limiting asynchronous requests without blocking

i am after some advice/strategy on limiting http requests when consuming multiple web services. I feel i could do this if the requests were happening synchronously, but they are asynchronous and think i should try to perform the limit logic in a way that i wont block.
Due to the web app consuming multiple web services there will be different limits for different requests. I was thinking something like this, but aren't sure how to proceed in a no blocking manner:
request method:
public static Task<string> AsyncRequest(string url, enum webService)
{
using(LimitingClass limiter = new LimitingClass(webService))
{
//Perform async request
}
}
In the LimitingClass it will have logic like checking the last request for the given webservice, if it violates the limit then it will wait a certain amount of time. But in the mean time if another request comes in to a different webservice then i dont want that request to be blocked while the LimitingClass is waiting. Is there anything fundamentally wrong with the above approach? Should i open up a new thread with each LimitingClass instance?
Some pseudo code would be great if possible.
Many Thanks
UPDATE:
This is a simplified version of my current request method:
public static Task<string> MakeAsyncRequest(string url, string contentType)
{
HttpWebRequest request = //set up my request
Task<WebResponse> task = Task.Factory.FromAsync(
request.BeginGetResponse,
asyncResult => request.EndGetResponse(asyncResult),
(object)null);
return task.ContinueWith(t => ReadCallback(t.Result));
}
I just want to wrap this in a using to check the limits and which doesnt block other requests.
So how are you limiting an access to resource without blocking ?
I think you need to look at Semaphores - they allow to limits the number of threads that can access a resource or pool of resources concurrently.

Categories