gpt4 book ai didi

c# - 使用 Reactive Extensions 重试异步任务代码

转载 作者:太空狗 更新时间:2023-10-30 00:49:00 28 4
gpt4 key购买 nike

在我的数据访问类中包含以下代码。

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"));
}

最佳答案

我可以看到您的代码有几个潜在的问题:

  • 将重试逻辑与主逻辑分开,例如在名为 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();
}
}

关于c# - 使用 Reactive Extensions 重试异步任务代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41600715/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com