c# - 瞬态故障重试逻辑最佳实践
问题描述
朋友们,我有一个关于围绕 SQL 命令执行实现简单重试策略的问题。
我的问题是:重试循环应该封装连接和事务的构造,还是应该存在于连接内部。
例如:
private void RetryLogSave(DynamicParameters parameters, int retries = 3)
{
int tries = 0;
using (var connection = new SqlConnection(_connectionString))
{
connection.Open();
using (var transaction = connection.BeginTransaction())
{
var logItemCommand = new CommandDefinition(commandText: Constants.InsertLogItem,
parameters: parameters, transaction: transaction, commandType: System.Data.CommandType.Text);
do
{
try
{
tries++;
connection.Execute(logItemCommand);
transaction.Commit();
break;
}
catch (Exception exc)
{
if (tries == retries)
{
transaction.Rollback();
throw exc;
}
Task.Delay(100 * tries).Wait();
}
}
while (true);
}
}
}
我在这里所做的是否合适且可以接受,或者重试逻辑是否应该存在于 SqlConnection 构造之外?
解决方案
将我的评论形式化为答案。
重试逻辑是否应该存在于 SqlConnection 构造之外?
是的。如果在保持连接打开的情况下执行重试逻辑,那么您正在浪费资源。在您等待 N 秒重试时,其他人可能会使用它。打开/关闭连接通常(对于大多数 ODBC 驱动程序)在连接池机制之上实现。您实际上并没有关闭它 - 您允许连接回到池中以供其他人重用。在重试期间保持连接打开将迫使系统创建越来越多的新物理连接(因为它们没有返回到池中),最终您的 SQL Server 将耗尽。
关于重试机制——为了不重新发明轮子,我通常使用Polly库。
您可以在某处定义带有策略列表的静态类:
public static class MyPolices
{
// Retry, waiting a specified duration between each retry
public static Policy RetryPolicy = Policy
.Handle<Exception>() // can be more specific like SqlException
.WaitAndRetry(new[]
{
TimeSpan.FromSeconds(1),
TimeSpan.FromSeconds(2),
TimeSpan.FromSeconds(3)
});
}
然后,将您的方法简化为
private void LogSave(DynamicParameters parameters)
{
using (var connection = new SqlConnection(_connectionString))
{
connection.Open();
using (var transaction = connection.BeginTransaction())
{
// make sure to not forget to dispose your command
var logItemCommand = new CommandDefinition(commandText: Constants.InsertLogItem,
parameters: parameters, transaction: transaction, commandType: System.Data.CommandType.Text);
try
{
// not sure if conn.Execute is your extension method?
connection.Execute(logItemCommand);
transaction.Commit();
}
catch (Exception exc)
{
transaction.Rollback();
throw;
}
}
}
}
并这样称呼它
MyPolices.RetryPolicy.Execute(() => LogSave(parameters));
这种方法将使您的代码更加可靠,保持重试逻辑隔离。
推荐阅读
- python - 函数适用于数据框的每一行,但不使用 df.apply
- jenkins - 文件操作插件 fileCopyOperation - Jenkins 管道
- java - print values in c:forEach loop
- javascript - 如何使用 Angular 和 js 附加多个羽毛笔编辑器
- numpy - numpy 整数数组和位掩码
- bison - Bison accept input after rule done
- php - Bootstrap 下拉菜单与 Highcharts 导航按钮功能相同
- c# - 使用 Unity (C#) Android 应用程序检测 GearVR 中的 USB 驱动器
- c# - 使用后 C# 流为空
- php - Mailchimp v3 api 返回错误