在我的数据访问类中使用以下代码。
public async Task<IEnumerable<TEntity>> QueryAsync(string sql, object param = null,
CommandType commandType = CommandType.Text, int? commandTimeout = null, IDbTransaction transaction = null)
{
using (var connection = Connection)
{
var tokenSource = GetCancellationTokenSource(commandTimeout ?? CommandTimeoutDefault);
Task<IEnumerable<TEntity>> queryTask =
connection.QueryAsync<TEntity>(new CommandDefinition(sql, param, transaction,
commandTimeout ?? CommandTimeoutDefault, commandType, cancellationToken: tokenSource.Token));
IEnumerable<TEntity> data = await queryTask.ConfigureAwait(false);
connection.Close();
connection.Dispose();
tokenSource.Dispose();
return data;
}
}
我想要一个SqlExeption
抛出一次重试。请记住,我不能将RX应用于应用程序,而只能应用于此代码块。
我尝试了下面的代码,看起来它正在正确执行,Do
正在登录控制台输出,但并没有真正调用Catch
处理程序而我没有确定是否也执行Retry
处理程序。
public async Task<IEnumerable<TEntity>> QueryAsync(string sql, object param = null,
CommandType commandType = CommandType.Text, int? commandTimeout = null, IDbTransaction transaction = null)
{
return await Observable.Defer(async () =>
{
using (var connection = Connection)
{
var tokenSource = GetCancellationTokenSource(commandTimeout ?? CommandTimeoutDefault);
Task<IEnumerable<TEntity>> queryTask =
connection.QueryAsync<TEntity>(new CommandDefinition(sql, param, transaction,
commandTimeout ?? CommandTimeoutDefault, commandType, cancellationToken: tokenSource.Token));
IEnumerable<TEntity> data = await queryTask.ConfigureAwait(false);
connection.Close();
connection.Dispose();
tokenSource.Dispose();
return Observable.Return(data);
}
})
.Catch<IEnumerable<TEntity>, SqlException>(source =>
{
Debug.WriteLine($"QueryAsync Exception {source}");
return Observable.Return(new List<TEntity>());
})
.Throttle(TimeSpan.FromMilliseconds(500))
.Retry(1)
.Do(_ => Debug.WriteLine("Do QueryAsync"));
}
答案 0 :(得分:6)
我可以看到您的代码存在几个潜在问题:
QueryWithRetryAsync
的方法中,将重试逻辑与主逻辑分开。这只是一个设计问题,但仍然存在问题Catch
之后 Retry
。否则,SqlException
将导致空列表,Retry
运算符将永远不会看到异常Throttle
根本不是必需的,因为你只想通过管道获得一个值Retry(1)
没有按照你的想法做到(这对我来说也是一个惊喜)。似乎“重试”的定义包括第一次调用,因此您需要Retry(2)
以下是一个独立的示例,其行为方式符合您的要求:
class Program
{
static void Main(string[] args)
{
var pipeline = Observable
.Defer(() => DoSomethingAsync().ToObservable())
.Retry(2)
.Catch<string, InvalidOperationException>(ex => Observable.Return("default"));
pipeline
.Do(Console.WriteLine)
.Subscribe();
Console.ReadKey();
}
private static int invocationCount = 0;
private static async Task<string> DoSomethingAsync()
{
Console.WriteLine("Attempting DoSomethingAsync");
await Task.Delay(TimeSpan.FromSeconds(2));
++invocationCount;
if (invocationCount == 2)
{
return "foo";
}
throw new InvalidOperationException();
}
}