Это довольно классический случай использования Rx для опроса другой системы. Большинство людей будут использовать Observable.Interval
в качестве своего оператора, и для большинства это будет хорошо.
Однако у вас есть особые требования к таймаутам и повторным попыткам. В этом случае я думаю, что вы лучше использовать комбинацию операторов:
Observable.Timer
, чтобы позволить вам выполнить ваш запрос в указанное время
Timeout
для идентификации и запросов к базе данных, которые перерасход
ToObservable()
к сопоставьте полученные результаты Task
с наблюдаемой последовательностью.
Retry
, чтобы вы могли восстановить после тайм-аутов
Repeat
, чтобы вы могли продолжить работу после успешных запросов к базе данных. Это также сохранит этот начальный период/промежуток между завершением предыдущего запроса к базе данных и началом следующего.
Эта рабочая LINQPad сниппет должен показать вам запрос работает правильно:
void Main()
{
var pollingPeriod = TimeSpan.FromSeconds(5);
var dbQueryTimeout = TimeSpan.FromSeconds(10);
//You will want to have your Rx query timeout after the expected silence of the timer, and then further maximum silence.
var rxQueryTimeOut = pollingPeriod + dbQueryTimeout;
var scheduler = new EventLoopScheduler(ts => new Thread(ts) { Name = "DatabasePoller" });
var query = Observable.Timer(pollingPeriod, scheduler)
.SelectMany(_ => DatabaseQuery().ToObservable())
.Timeout(rxQueryTimeOut, Observable.Return("Timeout"), scheduler)
.Retry() //Loop on errors
.Repeat(); //Loop on success
query.StartWith("Seed")
.TimeInterval(scheduler) //Just to debug, print the timing gaps.
.Dump();
}
// Define other methods and classes here
private static int delay = 9;
private static int delayModifier = 1;
public async Task<string> DatabaseQuery()
{
//Oscillate the delay between 3 and 12 seconds
delay += delayModifier;
var timespan = TimeSpan.FromSeconds(delay);
if (delay < 4 || delay > 11)
delayModifier *= -1;
timespan.Dump("delay");
await Task.Delay(timespan);
return "Value";
}
Результаты выглядят:
Seed 00:00:00.0125407
Timeout 00:00:15.0166379
Timeout 00:00:15.0124480
Timeout 00:00:15.0004520
Timeout 00:00:15.0013296
Timeout 00:00:15.0140864
Value 00:00:14.0251731
Value 00:00:13.0231958
Value 00:00:12.0162236
Value 00:00:11.0138606
Ключевая часть образца ....
var query = Observable.Timer(TimeSpan.FromSeconds(5), scheduler)
.SelectMany(_ => DatabaseQuery().ToObservable())
.Timeout(rxQueryTimeOut, Observable.Return("Timeout"), scheduler)
.Retry() //Loop on errors
.Repeat(); //Loop on success
EDIT: Вот еще одно объяснение того, как прийти к этому решению. https://github.com/LeeCampbell/RxCookbook/blob/master/Repository/Polling.md
Вы можете добавить более подробную информацию? Какие данные возвращает запрос? запрос возвращает один объект? в случае таймаута вы говорите, что хотите, чтобы новый запрос запускался, что это за запрос? –