Http轮询,直到Rx满足请求

时间:2014-04-14 11:53:35

标签: .net rest observablecollection system.reactive polling

我从一个安静的api请求一个资源而不是http。资源需要时间才能达到“完整”状态,响应的http状态代码反映了资源的完整性。

调用客户端是等待消耗不想无限期等待的资源的用户。因此,api被轮询到获得“完整”资源的最大尝试次数。如果api返回指示资源已完成的状态,则资源将返回堆栈以供使用。如果api没有返回指示资源在最大尝试次数内完成的状态,那么客户端应该停止轮询并返回某种失败状态。

为了实现这一点,我正在使用Thread.Sleep(500)来阻止等待结果的线程。它让我做噩梦,想到这是多么低效,所以我希望改进这项技术。

我已经调查了Rx并徒劳地试图将Observable.Interval()弯曲到我的意愿,但我在调试线程上试图观察时遇到了麻烦。我理想地想知道我的代码应该是什么样的!目前在:

 Observable.Interval(TimeSpan.FromMilliseconds(500))
           .ObserveOn(SynchronizationContext.Current)
           .Take(10)
           .Subscribe(i =>
               {
                  // check if resource is complete
               });

2 个答案:

答案 0 :(得分:1)

Observable.FromAsync(token => restSharpClient.ExecuteTaskAsync(request, token))
    .SelectMany(response =>
        response.Data.HasCompleted
            ? Observable.Return(response)
            : Observable.ThrowException(new Exception("Resource not ready."))
                .DelaySubscription(TimeSpan.FromSeconds(5))
        )
    .Retry(10);

答案 1 :(得分:0)

我最终采用了TPL路线。我通过使用Task.Delay避免了显式的Thread.Sleep,它至少可以引用一个名称空间。

public class HttpRequestRetrierResponseContainer<T>
{
    public T Value { get; set; }
    public bool IsCriteriaMet { get; set; }
    public int AttemptCount { get; set; }
}

public class HttpRequestRetrier
{
    private readonly IHttpClientWrapper _httpClientWrapper;

    public HttpRequestRetrier(IHttpClientWrapper httpClientWrapper)
    {
        _httpClientWrapper = httpClientWrapper;
    }

    public async Task<HttpRequestRetrierResponseContainer<T>> RepeatRequestUntilResponseMeetsCriteria<T>(Func<HttpRequestMessage> getMessage, Predicate<HttpResponseMessage> criteria, int maxAttempts)
    {
        return await Attempt<T>(getMessage, criteria, maxAttempts, 0);
    }

    private async Task<HttpRequestRetrierResponseContainer<T>> Attempt<T>(Func<HttpRequestMessage> getMessage, Predicate<HttpResponseMessage> criteria, int maxAttempts, int attemptCount)
    {
        if (attemptCount < maxAttempts)
        {
            var response = await _httpClientWrapper.SendMessageAsync(getMessage);

            if (criteria(response))
            {
                var value = await response.Extensions().ReadAsAsync<T>();
                return new HttpRequestRetrierResponseContainer<T> { IsCriteriaMet = true, AttemptCount = attemptCount, Value = value };
            }

            Task.Delay(500).Wait();

            return await Attempt<T>(getMessage, criteria, maxAttempts, attemptCount + 1);
        }

        return new HttpRequestRetrierResponseContainer<T> { IsCriteriaMet = false };
    }
}
相关问题