【发布时间】:2019-08-30 15:00:48
【问题描述】:
我很困惑如何为以下代码实现取消/重试机制,为了简洁起见,它主要是伪代码:
class CLI {
async void Main() {
var response = await bot.GetSomething(); // final usage
}
}
class Bot {
private void StartTask() {
_taskCompSource = new TaskCompletionSource<object>();
}
private async Task<T> ResultPromise<T>() {
return await _taskCompSource.Task.ContinueWith(t => t.Result != null ? (T)t.Result : default(T));
}
// send request
public Task<string> GetSomething() {
StartTask();
QueueRequest?.Invoke(this, new Request(...)); // complex non-sync request, fired off here
return ResultPromise<string>();
}
// receive response
public void Process(Reply reply) {
// process reply
_taskCompSource.SetResult("success");
}
}
class BotManager {
// bot.QueueRequest += QueueRequest;
// _service.ReplyReceived += ReplyReceived;
private void QueueRequest(object sender, Request request) {
_service.QueueRequestForSending(request);
}
private async void ReplyReceived(object sender, Reply reply) {
GetBot().Process(reply);
}
}
class Service {
private Dictionary<string, Queue<Request>> _queues;
// send receive loop
private async void HttpCallback(IAsyncResult result) {
while (true) {
// if reply received then call ReplyReceived?.Invoke(this, reply);
// check if request already in progress // ##ISSUE IS HERE##
// if not send another request
// keep connection to server open by feeding spaces
}
}
public void QueueRequestForSending(Request request) {
GetQueueForBot().Enqueue(request);
}
}
我想在await bot.GetSomething(); 上实现超时,但不确定如何处理这种断开连接的性质。我试过了:
static class Extensions {
private static async Task<T> RunTaskWithRetry<T>(Func<Task<T>> taskFunc, int retries, int timeout) {
do {
var task = taskFunc(); // just adds another request to queue which never gets ran because the previous one is waited forever to return, this needs to cancel the previous request, from here, but how?
await Task.WhenAny(task, Task.Delay(timeout)).ConfigureAwait(false);
if (task.Status == TaskStatus.RanToCompletion) {
return task.Result;
}
retries--;
}
while (retries > 0);
return default(T);
}
public async static Task<T> WithRetry<T>(this Task<T> task, int retries = 3, int timeout = 10000) {
return await RunTaskWithRetry(async () => await task, retries, timeout);
}
}
可以像await bot.GetSomething().WithRetry(); 一样调用它,但这里的问题是它只是将另一个请求添加到队列中,而不是取消或删除现有的请求。要取消,我只需从awaiting 列表中删除现有请求。问题是我不知道如何从扩展方法的位置一路做到这一点。
我想知道我可以用来实现超时和取消的任何可能机制。
【问题讨论】:
标签: c# async-await timeout task cancellation