I'm using Polly version 7.1.1
I have a simple Polly retry policy that will retry an operation once if it fails with an 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");
I have a method that attempts to connect to a PostgreSQL database and run a query using said policy:
using (var conn = new NpgsqlConnection("myConnectionString"))
{
conn.Open()
using(var command = GetCommand())
{
policy.Execute(
action: context => command.ExecuteNonQuery(),
contextData: new Context("Command.ExecuteNonQuery"));
}
}
The method fails, gets retried, and the logger prints the following:
Retry 1 of , due to 42P01: relation "myDatabase" does not exist
I would expect the following to be logged:
Retry 1 of Command.ExecuteNonQuery, due to 42P01: relation "myDatabase" does not exist
Why is OperationKey
empty when the policy logs the retry?
EDIT: Adding a simplified console application as an example.
This prints the following to the console:
Retry 1 of , due to Testing Polly
Error.
Example:
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");
}
}
}
The Context object
OperationKey
,PolicyKey
,CorrelationId
)IDictionary<string, object>
interface to let the consumer provide any key-value pairs.If you look at this line of the source code or the documentation you can see that there is a constructor overload which accepts the
OperationKey
.So you define your Execute call like this:
In my opinion it is a bit better approach since you are not relying on string-based key insertion and retrieval.
UPDATE: I've found the problem.
You have been using a wrong overload of
Execute
.Use
context
instead ofcontextData
and theOperationKey
will present.