为什么我的 Polly 重试策略中的 OperationKey 为空?

Why is OperationKey empty in my Polly retry policy?

我使用的是 Polly 版本 7.1.1

我有一个简单的 Polly 重试策略,它会在操作失败时重试一次 NpgsqlException:

var policy = Policy
    .Handle<NpgsqlException>()
    .Retry(
        retryCount: 1,
        onRetry: (exception, retryCount, context) =>
        {
            _logger.Log(LogLevel.Warning, $"Retry {retryCount} of {context.OperationKey}, due to {exception.Message}", exception);
        })
    .WithPolicyKey("PostgresConnectionPolicy");

我有一个尝试连接到 PostgreSQL 数据库的方法和 运行 使用上述策略的查询:

using (var conn = new NpgsqlConnection("myConnectionString"))
{
    conn.Open()

    using(var command = GetCommand())
    {
        policy.Execute(
            action: context => command.ExecuteNonQuery(),
            contextData: new Context("Command.ExecuteNonQuery"));
    }
}

该方法失败,重试,记录器打印以下内容:

Retry 1 of , due to 42P01: relation "myDatabase" does not exist

我希望记录以下内容:

Retry 1 of Command.ExecuteNonQuery, due to 42P01: relation "myDatabase" does not exist

为什么策略记录重试时 OperationKey 为空?

编辑: 添加一个简化的控制台应用程序作为示例。

这会将以下内容打印到控制台:

Retry 1 of , due to Testing Polly
Error.

示例:

using Polly;
using System;

namespace TestPolly
{
    class Program
    {
        static void Main(string[] args)
        {
            var policy = Policy
                .Handle<Exception>()
                .Retry(
                    retryCount: 1,
                    onRetry: (exception, retryCount, context) =>
                    {
                        Console.WriteLine($"Retry {retryCount} of {context.OperationKey}, due to {exception.Message}");
                    })
                .WithPolicyKey("PostgresConnectionPolicy");

            try
            {
                policy.Execute(
                    action: context => TestPolly(),
                    contextData: new Context("TestPolly"));
            }
            catch (Exception e)
            {
                Console.WriteLine("Error.");
            }

            Console.ReadKey();
        }

        private static void TestPolly()
        {
            throw new Exception("Testing Polly");
        }
    }
}

改用自定义上下文解决了这个问题。

政策:

var policy = Policy
            .Handle<NpgsqlException>()
            .Retry(
                retryCount: 1,
                onRetry: (exception, retryCount, context) =>
                {
                    _logger.Log(LogLevel.Warning, $"Retry {retryCount} of {context["Operation"]}, due to {exception.Message}", exception);
                })
            .WithPolicyKey("PostgresConnectionPolicy");

执行:

policy.Execute(
    action: context => command.ExecuteNonQuery(),
    contextData: new Context() { { "Operation", "Command.ExecuteNonQuery()" } });

上下文对象

  • 定义了一些predefined fields(如OperationKeyPolicyKeyCorrelationId
  • implements IDictionary<string, object> 界面让消费者提供任何 key-value 对。

如果您查看 this line of the source code or the documentation,您会发现有一个构造函数重载接受 OperationKey.

因此,您可以这样定义执行调用:

policy.Execute(
    action: context => command.ExecuteNonQuery(),
    contextData: new Context("Command.ExecuteNonQuery()"));

我认为这是一种更好的方法,因为您不依赖 string-based 密钥插入和检索。


更新:我发现了问题。

您一直在使用错误的重载 Execute

policy.Execute(
    action: context => command.ExecuteNonQuery(),
    context: new Context("Command.ExecuteNonQuery()"));

使用 context 而不是 contextData 并且 OperationKey 将会出现。