I'm new to Rx and I'm trying to create an Observable sequence that will allow me to do the following:
I've been playing around with:
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "Some URI");
...
CancellationTokenSource tokenSource = new CancellationTokenSource();
CancellationToken token = tokenSource.Token;
...
try
{
var res = Observable.FromAsync(() => _client.SendAsync(request, token))
.Timeout(TimeSpan.FromSeconds(5));
try
{
HttpResponseMessage response = res.Wait();
// Process response
...
}
catch (TaskCancelledException)
{
....
}
}
catch (TimeoutException)
{
....
}
but I'm not sure of the best way to kick off the request again after a timeout occurs, and also how I should check that I have reached the max. number of retries.
Also, I'm not sure whether I should be putting a timeout policy on the observable sequence or whether I should be setting the Timeout property on the HttpClient object itself.
[Edited on 11 Dec 2014]
Based on comments below, I have updated the code from @TheZenCoder so that it uses an await
var attempts = 0;
HttpResponseMessage response = null;
try
{
response = await Observable
.FromAsync((ct) =>
{
attempts++;
return SendRequest(token, ct);
})
.Retry(5)
.LastAsync();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
I've only done limited testing so far but it seems to work ok.
For sending the request, setting a request timeout and using a cancellation token you can wrap that into a method like:
private static Task<HttpResponseMessage> SendRequest(CancellationToken token)
{
var client = new HttpClient { Timeout = TimeSpan.FromSeconds(5) };
var request = new HttpRequestMessage(HttpMethod.Get, new Uri("http://www.google.ba"));
return client.SendAsync(request, token);
}
I think setting the timeout on the HTTP client is a cleaner option instead of using the Observable timeout.
Then you can use the IObservable Retry
method to retry this operation multiple times. If you are not afraid of opensource there are also some more flexible retry methods in the RXX Extensions as noted by @Dave Sexton in the comments.
var attempts = 0;
try
{
var response = Observable
.FromAsync(() =>
{
attempts++;
return SendRequest(token);
})
.Retry(5)
.Wait();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
If an HTTP timeout or another error occurs in the SendRequest
method the retries will continue. An exception will be thrown after the last retry containing information about the error. The number of retries is set to the attempts variable.
Have in mind that using the Wait
method effectively blocks the calling thread execution until a result is available, and that is not something you ever want to do when using Async code. Maybe you have some specific scenario on mind, and that is why i left it there in my example.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With