Skip to content

Keys and Context Data

reisenberger edited this page Mar 7, 2019 · 11 revisions

What is Context?

An execution-scoped instance of the Polly.Context class travels with every execution through a Polly policy.

The role of this class is to provide execution context and to allow the exchange of information between the pre-execution, mid-execution, and post-execution phases.

What information can Context carry?

Context carries two kinds of information:

  • Values for pre-defined keys - these can uniquely identify the policy in use, policywrap in use, execution call site, and a unique correlation-id per execution.
  • Custom data - you can add any custom data to Context, using Dictionary<string, object> semantics.

Where is Context available?

The context instance travelling with the execution is available:

  • before execution (if you define it yourself and pass it in)
  • to the main delegate .Execute/Async(...)-d through the policy (when you use an overload taking Context)
  • to every delegate hook (onRetry, onBreak etc)
  • after execution.

It can therefore be used to pass information into executions, get information out of executions, and exchange information among any part of a policy execution.

Pre-defined keys on Context

The following four pre-defined keys are available as properties directly on Context:

| Key | Scope (ie unique to) | How to set? | Default
(if not set) |Purpose| | --- | --- | --- | --- | --- |--- | | PolicyWrapKey | PolicyWrap instance

(in nested wrap, takes outermost specified value)|policyWrap .WithPolicyKey("someValue")|PolicyWrap-partguid;

ornull if no PolicyWrap in use|Indicate the PolicyWrap in use| | PolicyKey | Policy instance | policy .WithPolicyKey("someValue")|PolicyType-partguid |Indicate the Policy in use| | OperationKey | call site
(if code specifies it) |pass new Context("someOperationKey") into the Execute call | null |Indicate where the policy in use

Used by CachePolicy as the cache key for the execution | | CorrelationId | an individual execution | not user-settable |a unique guid | Uniquely correlate logs/ metrics for a single execution|

Changes between Polly <v6 and >=v6

OperationKey was named ExecutionKey prior to v6.

CorrelationId was named ExecutionGuid prior to v6.

Using pre-defined keys: examples

// Identify policies with a PolicyKey, using the WithPolicyKey() extension method
// (for example, for correlation in logs or metrics)

var policy = Policy
    .Handle<DataAccessException>()
    .Retry(3, onRetry: (exception, retryCount, context) =>
       {
           logger.Error($"Retry {retryCount} of {context.PolicyKey} at {context.OperationKey}, due to: {exception}.");
       })
    .WithPolicyKey("MyDataAccessPolicy");

// Identify call sites with an OperationKey, by passing in a Context
var customerDetails = policy.Execute(myDelegate, new Context("GetCustomerDetails"));

// "MyDataAccessPolicy" -> context.PolicyKey 
// "GetCustomerDetails  -> context.OperationKey

Using Context for custom data

Context has full Dictionary<object, string> semantics. You can set data on an instance of Context

var context = new Polly.Context();
context["MyCustomData"] = foo;

and get it back later, for example within an onRetry hook or within the delegate executed:

var myFooFromElsewhere = context["MyCustomData"];

Use Case:

Use Case: Varying the ILogger used within an onRetry delegate

A common use of Context is to bridge the fact that policies are often defined (including policy callback delegates) on startup; but some information you want to use within the delegate hooks (such as an ILogger) might only be available, due to dependency injection, at the call site.

// Pass additional custom information from call site into the context
var policy = Policy
    .Handle<DataAccessException>()
    .Retry(3, onRetry: (exception, retryCount, context) =>
       {
           logger.Error($"Retry {retryCount} of {context.PolicyKey} at {context.OperationKey}, getting {context["Type"]} of id {context["Id"]}, due to: {exception}.  CorrelationId: {context.CorrelationId}");
       })
    .WithPolicyKey("MyDataAccessPolicy");

int id = ... // customer id from somewhere
var customerDetails = policy.Execute(() => GetCustomer(id), 
    new Context($"GetCustomer-{Id}", new Dictionary<string, object>() {{"Type","Customer"},{"Id",id}}
    ));

Using Context with policies configured via HttpClientFactory

See the notes in the Polly with HttpClientFactory page.

Clone this wiki locally