Azure Durable Functions SQL异常处理:终止执行及日志查询方案
Azure Durable Functions SQL操作异常处理实现方案
Activity层异常处理逻辑
首先修正你示例代码中的基础拼写问题:.NET中SQL客户端类为SqlConnection/SqlCommand,执行方法为ExecuteReader,且using代码块会在执行结束后自动释放连接资源,无需手动调用conn.Close()。
异常处理核心逻辑:
- 将所有SQL连接、执行逻辑包裹在
try/catch块中,优先捕获SQL操作专属的SqlException类型,覆盖连接失败、存储过程语法错误、执行逻辑报错、权限不足等所有数据库侧异常 - 捕获到异常后,附带业务上下文信息(业务标识、执行参数、错误编号)后直接抛出,不做异常吞没,Activity会立即终止执行,异常会自动透传到上层编排函数
- 非SQL类的通用异常(比如参数空引用、序列化失败)同样捕获后透传,避免静默失败
完整Activity代码示例:
using Microsoft.Data.SqlClient; using System.Data; // 存储过程执行成功返回结构 public class SpExecutionOutput { public List<Dictionary<string, object>> QueryRecords { get; set; } } [FunctionName("Activity_ExecuteStoredProcedure")] public static async Task<SpExecutionOutput> ExecuteStoredProcedure( [ActivityTrigger] (string BusinessId, Dictionary<string, object> SpParameters) input, ILogger log) { var connStr = Environment.GetEnvironmentVariable("sqldb_connection"); try { using var conn = new SqlConnection(connStr); await conn.OpenAsync(); using var cmd = new SqlCommand("Stored_procedure", conn) { CommandType = CommandType.StoredProcedure, CommandTimeout = 30 // 根据存储过程执行时长调整超时时间 }; // 自动填充存储过程入参 if (input.SpParameters != null) { foreach (var param in input.SpParameters) { cmd.Parameters.AddWithValue(param.Key, param.Value ?? DBNull.Value); } } var result = new List<Dictionary<string, object>>(); using var reader = await cmd.ExecuteReaderAsync(); while (await reader.ReadAsync()) { var row = new Dictionary<string, object>(); for (int i = 0; i < reader.FieldCount; i++) { row.Add(reader.GetName(i), reader.IsDBNull(i) ? null : reader.GetValue(i)); } result.Add(row); } return new SpExecutionOutput { QueryRecords = result }; } catch (SqlException ex) { var errorMsg = $"存储过程执行失败,业务ID:{input.BusinessId},SQL错误号:{ex.Number},错误信息:{ex.Message}"; log.LogError(ex, errorMsg); // 抛出异常终止Activity执行 throw new InvalidOperationException(errorMsg, ex); } catch (Exception ex) { var errorMsg = $"存储过程执行出现非预期错误,业务ID:{input.BusinessId},错误信息:{ex.Message}"; log.LogError(ex, errorMsg); throw new InvalidOperationException(errorMsg, ex); } }
编排层异常捕获与重试
编排函数调用Activity时,通过try/catch捕获异常,同时可利用Durable Functions原生的重试策略对可重试错误(比如连接超时、死锁)做自动重试,重试耗尽后进入失败处理逻辑,不会执行后续业务流程。
示例代码:
[FunctionName("Orchestrator_MainBusinessFlow")] public static async Task RunMainFlow( [OrchestrationTrigger] IDurableOrchestrationContext context, ILogger log) { var businessInput = context.GetInput<(string BusinessId, Dictionary<string, object> SpParameters)>(); try { // 重试策略:最多重试3次,首次间隔5秒,后续间隔按指数递增 var retryPolicy = new RetryOptions(TimeSpan.FromSeconds(5), 3) { BackoffCoefficient = 2, // 仅对连接错误、死锁错误重试,存储过程逻辑错误、语法错误不重试 Handle = ex => ex.InnerException is SqlException sqlEx && (sqlEx.Number == 1205 || sqlEx.Number == 10060 || sqlEx.Number == 40197) }; // 调用带重试的Activity,执行失败且重试耗尽时会抛出异常 var spResult = await context.CallActivityWithRetryAsync<SpExecutionOutput>( "Activity_ExecuteStoredProcedure", retryPolicy, businessInput); // 仅存储过程执行成功才会走到后续流程 await context.CallActivityAsync("Activity_NextBusinessStep", spResult); } catch (Exception ex) { // 构造失败信息 var failureInfo = new { BusinessId = businessInput.BusinessId, InstanceId = context.InstanceId, ErrorMessage = ex.Message, FailedAtUtc = context.CurrentUtcDateTime, StackTrace = ex.StackTrace }; // 触发失败处理:持久化错误、通知用户 await context.CallActivityAsync("Activity_ProcessFailure", failureInfo); // 标记编排实例为失败状态 throw; } }
失败信息存储方案
可选三种主流存储方式,可根据实际运维需求选择:
- 自定义业务表存储:在现有Azure SQL中新建执行失败记录表,在
Activity_ProcessFailure中写入失败信息,表字段建议包含业务ID、编排实例ID、错误信息、异常堆栈、失败时间、处理状态。这种方式最贴合业务查询习惯。 - Durable Functions原生实例存储:Durable Functions默认会将所有编排实例的状态、异常信息存在TaskHub关联的Azure Storage账号中,无需额外开发存储逻辑,所有失败信息自动持久化。
- Application Insights存储:为函数应用配置Application Insights后,所有异常、执行日志会自动上报,自带全链路追踪ID,适合问题排查。
失败记录检索方法
对应不同存储方式的检索路径:
- 自定义表存储:直接通过SQL语句按业务ID、时间范围、处理状态筛选查询即可,示例:
SELECT * FROM SpExecutionFailures WHERE BusinessId = @QueryBusinessId AND FailedAtUtc BETWEEN @StartTime AND @EndTime - 原生实例存储检索:
- 通过Durable Functions客户端的
GetStatusAsync方法,传入编排实例ID即可获取完整失败详情 - 直接查询TaskHub对应的
Instances表,筛选RuntimeStatus = 'Failed'的记录,可按实例ID、创建时间范围过滤 - 通过Azure Portal的Durable Functions监控面板,按实例状态、时间筛选失败实例查看详情
- 通过Durable Functions客户端的
- Application Insights检索:在日志查询界面通过Kusto语句查询,示例:
exceptions | where timestamp > ago(30d) | where operation_Name == "Activity_ExecuteStoredProcedure" | where customDimensions.BusinessId == "查询的业务ID" | project timestamp, message, customDimensions, stacktrace
内容的提问来源于stack exchange,提问作者Termigez
相关产品推荐
相关产品推荐

