Skip to content

Commit 41fd38c

Browse files
authored
[Docs] Revise migration guide 3/3 (#1775)
1 parent 61c959c commit 41fd38c

File tree

5 files changed

+155
-76
lines changed

5 files changed

+155
-76
lines changed

docs/migration-v8.md

+108-51
Original file line numberDiff line numberDiff line change
@@ -409,7 +409,7 @@ new ResiliencePipelineBuilder<HttpResponseMessage>().AddRetry(new RetryStrategyO
409409
> Things to remember:
410410
>
411411
> - Use `AddRetry` to add a retry strategy to your resiliency pipeline
412-
> - Use the `RetryStrategyOptions` to customize your retry behavior to meet your requirements
412+
> - Use the `RetryStrategyOptions{<TResult>}` to customize your retry behavior to meet your requirements
413413
>
414414
> For further information please check out the [Retry resilience strategy documentation](strategies/retry.md).
415415
@@ -689,7 +689,7 @@ cbPolicy.Reset(); // Transitions into the Closed state
689689

690690
### Circuit breaker in v8
691691

692-
> [!TIP]
692+
> [!NOTE]
693693
>
694694
> Polly V8 does not support the standard (*"classic"*) circuit breaker with consecutive failure counting.
695695
>
@@ -769,23 +769,24 @@ ____
769769
>
770770
> For further information please check out the [Circuit Breaker resilience strategy documentation](strategies/circuit-breaker.md).
771771
772-
## Migrating other policies
772+
## Migrating `Polly.Context`
773773

774-
Migrating is a process similar to the ones described in the previous sections. Keep in mind that:
774+
The successor of the `Polly.Context` is the `ResilienceContext`. The major differences:
775775

776-
- Strategy configurations (or policies in v7) are now in options. Property names should match the v7 APIs and scenarios.
777-
- Use `ResiliencePipelineBuilder` or `ResiliencePipelineBuilder<T>` and their respective extensions to add specific strategies.
778-
- For more details on each strategy, refer to the [resilience strategies](strategies/index.md) documentation.
776+
- `ResilienceContext` is pooled for enhanced performance and cannot be directly created. Instead, use the `ResilienceContextPool` class to get an instance.
777+
- `Context` allowed directly custom data attachment, whereas `ResilienceContext` employs the `ResilienceContext.Properties` for the same purpose.
778+
- In order to set or get a custom data you need to utilize the generic `ResiliencePropertyKey` structure.
779779

780-
## Migrating `Polly.Context`
780+
### Predefined keys
781781

782-
`Polly.Context` has been succeeded by `ResilienceContext`. Here are the main changes:
782+
| In V7 | In V8 |
783+
| :-- | :-- |
784+
| `OperationKey` | It can be used in the same way |
785+
| `PolicyKey` | It's been relocated to `ResiliencePipelineBuilder` and used for [telemetry](advanced/telemetry.md#metrics) |
786+
| `PolicyWrapKey` | It's been relocated to `ResiliencePipelineBuilder` and used for [telemetry](advanced/telemetry.md#metrics) |
787+
| `CorrelationId` | It's been removed. For similar functionality, you can either use `System.Diagnostics.Activity.Current.Id` or attach your custom Id using `ResilienceContext.Properties`. |
783788

784-
- `ResilienceContext` is pooled for enhanced performance and cannot be directly created. Instead, use the `ResilienceContextPool` class to get an instance.
785-
- Directly attaching custom data is supported by `Context`, whereas `ResilienceContext` employs the `ResilienceContext.Properties` property.
786-
- Both `PolicyKey` and `PolicyWrapKey` are no longer a part of `ResilienceContext`. They've been relocated to `ResiliencePipelineBuilder` and are now used for [telemetry](advanced/telemetry.md#metrics).
787-
- The `CorrelationId` property has been removed. For similar functionality, you can either use `System.Diagnostics.Activity.Current.Id` or attach your custom Id using `ResilienceContext.Properties`.
788-
- Additionally, `ResilienceContext` introduces the `CancellationToken` property.
789+
- Additionally, `ResilienceContext` introduces a new property for `CancellationToken`.
789790

790791
### `Context` in v7
791792

@@ -798,12 +799,19 @@ Context context = new Context();
798799
context = new Context("my-operation-key");
799800

800801
// Attach custom properties
801-
context["prop-1"] = "value-1";
802-
context["prop-2"] = 100;
802+
context[Key1] = "value-1";
803+
context[Key2] = 100;
803804

804805
// Retrieve custom properties
805-
string value1 = (string)context["prop-1"];
806-
int value2 = (int)context["prop-2"];
806+
string value1 = (string)context[Key1];
807+
int value2 = (int)context[Key2];
808+
809+
// Bulk attach
810+
context = new Context("my-operation-key", new Dictionary<string, object>
811+
{
812+
{ Key1 , "value-1" },
813+
{ Key2 , 100 }
814+
});
807815
```
808816
<!-- endSnippet -->
809817

@@ -818,19 +826,36 @@ ResilienceContext context = ResilienceContextPool.Shared.Get();
818826
context = ResilienceContextPool.Shared.Get("my-operation-key");
819827

820828
// Attach custom properties
821-
context.Properties.Set(new ResiliencePropertyKey<string>("prop-1"), "value-1");
822-
context.Properties.Set(new ResiliencePropertyKey<int>("prop-2"), 100);
829+
ResiliencePropertyKey<string> propertyKey1 = new(Key1);
830+
context.Properties.Set(propertyKey1, "value-1");
831+
832+
ResiliencePropertyKey<int> propertyKey2 = new(Key2);
833+
context.Properties.Set(propertyKey2, 100);
834+
835+
// Bulk attach
836+
context.Properties.SetProperties(new Dictionary<string, object?>
837+
{
838+
{ Key1 , "value-1" },
839+
{ Key2 , 100 }
840+
}, out var oldProperties);
823841

824842
// Retrieve custom properties
825-
string value1 = context.Properties.GetValue(new ResiliencePropertyKey<string>("prop-1"), "default");
826-
int value2 = context.Properties.GetValue(new ResiliencePropertyKey<int>("prop-2"), 0);
843+
string value1 = context.Properties.GetValue(propertyKey1, "default");
844+
int value2 = context.Properties.GetValue(propertyKey2, 0);
827845

828846
// Return the context to the pool
829847
ResilienceContextPool.Shared.Return(context);
830848
```
831849
<!-- endSnippet -->
832850

833-
For more details, refer to the [Resilience Context](advanced/resilience-context.md) documentation.
851+
> [!TIP]
852+
>
853+
> Things to remember:
854+
>
855+
> - Use `ResilienceContextPool.Shared` to get a context and return it back to the pool
856+
> - Use the `ResiliencePropertyKey<TValue>` to define type-safe keys for your custom data
857+
>
858+
> For further information please check out the [Resilience Context documentation](advanced/resilience-context.md).
834859
835860
## Migrating safe execution
836861

@@ -862,35 +887,40 @@ if (policyResult.Outcome == OutcomeType.Successful)
862887
else
863888
{
864889
Exception exception = policyResult.FinalException;
865-
FaultType failtType = policyResult.FaultType!.Value;
890+
FaultType faultType = policyResult.FaultType!.Value;
866891
ExceptionType exceptionType = policyResult.ExceptionType!.Value;
867892

868893
// Process failure
869894
}
870895

871896
// Access context
897+
const string Key = "context_key";
872898
IAsyncPolicy<int> asyncPolicyWithContext = Policy.TimeoutAsync<int>(TimeSpan.FromSeconds(10),
873899
onTimeoutAsync: (ctx, ts, task) =>
874900
{
875-
ctx["context_key"] = "context_value";
901+
ctx[Key] = "context_value";
876902
return Task.CompletedTask;
877903
});
878904

879905
asyncPolicyResult = await asyncPolicyWithContext.ExecuteAndCaptureAsync((ctx, token) => MethodAsync(token), new Context(), CancellationToken.None);
880-
string? ctxValue = asyncPolicyResult.Context.GetValueOrDefault("context_key") as string;
906+
string? ctxValue = asyncPolicyResult.Context.GetValueOrDefault(Key) as string;
881907
```
882908
<!-- endSnippet -->
883909

884910
### `ExecuteOutcomeAsync` in V8
885911

912+
> [!NOTE]
913+
>
914+
> Polly V8 does not provide an API to synchronously execute and capture the outcome of a pipeline.
915+
886916
<!-- snippet: migration-execute-v8 -->
887917
```cs
888918
ResiliencePipeline<int> pipeline = new ResiliencePipelineBuilder<int>()
889919
.AddTimeout(TimeSpan.FromSeconds(1))
890920
.Build();
891921

892922
// Synchronous execution
893-
// Polly v8 does not provide an API to synchronously execute and capture the outcome of a pipeline
923+
// Polly v8 does not support
894924
895925
// Asynchronous execution
896926
var context = ResilienceContextPool.Shared.Get();
@@ -938,82 +968,109 @@ ResilienceContextPool.Shared.Return(context);
938968
```
939969
<!-- endSnippet -->
940970

971+
> [!TIP]
972+
>
973+
> Things to remember:
974+
>
975+
> - Use `ExecuteOutcomeAsync` to execute your callback in a safe way
976+
941977
## Migrating no-op policies
942978

943-
- For `Policy.NoOp` or `Policy.NoOpAsync`, switch to `ResiliencePipeline.Empty`.
944-
- For `Policy.NoOp<T>` or `Policy.NoOpAsync<T>`, switch to `ResiliencePipeline<T>.Empty`.
979+
| In V7 | In V8 |
980+
| :-- | :-- |
981+
| `Policy.NoOp` | `ResiliencePipeline.Empty` |
982+
| `Policy.NoOpAsync` | `ResiliencePipeline.Empty` |
983+
| `Policy.NoOp<TResult>` | `ResiliencePipeline<TResult>.Empty` |
984+
| `Policy.NoOpAsync<TResult>` | `ResiliencePipeline<TResult>.Empty` |
945985

946986
## Migrating policy registries
947987

948988
In v7, the following registry APIs are exposed:
949989

950-
- `IPolicyRegistry<T>`
951-
- `IReadOnlyPolicyRegistry<T>`
952-
- `IConcurrentPolicyRegistry<T>`
953-
- `PolicyRegistry<T>`
990+
- `IConcurrentPolicyRegistry<TKey>`
991+
- `IPolicyRegistry<TKey>`
992+
- `IReadOnlyPolicyRegistry<TKey>`
993+
- `PolicyRegistry<TKey>`
954994

955995
In v8, these have been replaced by:
956996

957997
- `ResiliencePipelineProvider<TKey>`: Allows adding and accessing resilience pipelines.
958998
- `ResiliencePipelineRegistry<TKey>`: Read-only access to resilience pipelines.
959999

960-
The main updates in the new registry include:
1000+
The main updates:
9611001

962-
- It's append-only, which means removal of items is not supported to avoid race conditions.
1002+
- It's **append-only**, which means removal of items is not supported to avoid race conditions.
9631003
- It's thread-safe and supports features like dynamic reloading and resource disposal.
964-
- It allows dynamic creation and caching of resilience pipelines (previously known as policies in v7) using pre-registered delegates.
1004+
- It allows dynamic creation and caching of resilience pipelines using pre-registered delegates.
9651005
- Type safety is enhanced, eliminating the need for casting between policy types.
9661006

967-
For more details, refer to the [pipeline registry](pipelines/resilience-pipeline-registry.md) documentation.
968-
9691007
### Registry in v7
9701008

9711009
<!-- snippet: migration-registry-v7 -->
9721010
```cs
9731011
// Create a registry
9741012
var registry = new PolicyRegistry();
9751013

1014+
// Add a policy
1015+
registry.Add(PolicyKey, Policy.Timeout(TimeSpan.FromSeconds(10)));
1016+
9761017
// Try get a policy
977-
registry.TryGet<IAsyncPolicy>("my-key", out IAsyncPolicy? policy);
1018+
registry.TryGet<IAsyncPolicy>(PolicyKey, out IAsyncPolicy? policy);
9781019

9791020
// Try get a generic policy
980-
registry.TryGet<IAsyncPolicy<string>>("my-key", out IAsyncPolicy<string>? genericPolicy);
981-
982-
// Add a policy
983-
registry.Add("my-key", Policy.Timeout(TimeSpan.FromSeconds(10)));
1021+
registry.TryGet<IAsyncPolicy<string>>(PolicyKey, out IAsyncPolicy<string>? genericPolicy);
9841022

9851023
// Update a policy
9861024
registry.AddOrUpdate(
987-
"my-key",
1025+
PolicyKey,
9881026
Policy.Timeout(TimeSpan.FromSeconds(10)),
9891027
(key, previous) => Policy.Timeout(TimeSpan.FromSeconds(10)));
9901028
```
9911029
<!-- endSnippet -->
9921030

9931031
### Registry in v8
9941032

1033+
> [!NOTE]
1034+
>
1035+
> Polly V8 does not provide an explicit API to directly update a strategy in the registry.
1036+
>
1037+
> On the other hand it does provide a mechanism to [reload pipelines](pipelines/resilience-pipeline-registry.md#dynamic-reloads).
1038+
9951039
<!-- snippet: migration-registry-v8 -->
9961040
```cs
9971041
// Create a registry
9981042
var registry = new ResiliencePipelineRegistry<string>();
9991043

1044+
// Add a pipeline using a builder, when the pipeline is retrieved it will be dynamically built and cached
1045+
registry.TryAddBuilder(PipelineKey, (builder, context) => builder.AddTimeout(TimeSpan.FromSeconds(10)));
1046+
10001047
// Try get a pipeline
1001-
registry.TryGetPipeline("my-key", out ResiliencePipeline? pipeline);
1048+
registry.TryGetPipeline(PipelineKey, out ResiliencePipeline? pipeline);
10021049

10031050
// Try get a generic pipeline
1004-
registry.TryGetPipeline<string>("my-key", out ResiliencePipeline<string>? genericPipeline);
1005-
1006-
// Add a pipeline using a builder, when "my-key" pipeline is retrieved it will be dynamically built and cached
1007-
registry.TryAddBuilder("my-key", (builder, context) => builder.AddTimeout(TimeSpan.FromSeconds(10)));
1051+
registry.TryGetPipeline<string>(PipelineKey, out ResiliencePipeline<string>? genericPipeline);
10081052

10091053
// Get or add pipeline
1010-
registry.GetOrAddPipeline("my-key", builder => builder.AddTimeout(TimeSpan.FromSeconds(10)));
1054+
registry.GetOrAddPipeline(PipelineKey, builder => builder.AddTimeout(TimeSpan.FromSeconds(10)));
10111055
```
10121056
<!-- endSnippet -->
10131057

1058+
> [!TIP]
1059+
>
1060+
> Things to remember:
1061+
>
1062+
> - Use `ResiliencePipelineRegistry<TResult>` to add or get a pipelines to the registry
1063+
> - Prefer the safer methods (for example: `TryGetPipeline{<TResult>}`) over their counterpart (for example: `GetPipeline{<TResult>}`)
1064+
>
1065+
> For further information please check out the [Resilience pipeline registry documentation](pipelines/resilience-pipeline-registry.md).
1066+
10141067
## Interoperability between policies and resilience pipelines
10151068

1016-
In certain scenarios, you might not want to migrate your code to the v8 API. Instead, you may prefer to use strategies from v8 and apply them to v7 APIs. Polly provides a set of extension methods to support easy conversion from v8 to v7 APIs, as shown in the example below:
1069+
In certain scenarios, you might not able to migrate all your code to the v8 API.
1070+
1071+
In the name of interoperability you can define V8 strategies use them with your v7 policies.
1072+
1073+
V8 provides a set of extension methods to support easy conversion from v8 to v7 APIs, as shown in the example below:
10171074

10181075
> [!NOTE]
10191076
> In v8, you have to add the [`Polly.RateLimiting`](https://www.nuget.org/packages/Polly.RateLimiting) package to your application otherwise you won't see the `AddRateLimiter` extension.

docs/pipelines/resilience-pipeline-registry.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ The constructor for `ResiliencePipelineRegistry<TKey>` accepts a parameter of ty
9595
| `InstanceNameFormatter` | `null` | Delegate formatting `TKey` to instance name. |
9696
| `BuilderNameFormatter` | Function returning the `key.ToString()` value. | Delegate formatting `TKey` to builder name. |
9797

98-
> [>NOTE]
98+
> [!NOTE]
9999
> The `BuilderName` and `InstanceName` are used in [telemetry](../advanced/telemetry.md#metrics).
100100
101101
Usage example:

src/Snippets/Docs/Migration.Context.cs

+27-8
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
internal static partial class Migration
44
{
5+
private const string Key1 = nameof(Key1);
6+
private const string Key2 = nameof(Key2);
57
public static void Context_V7()
68
{
79
#region migration-context-v7
@@ -13,12 +15,19 @@ public static void Context_V7()
1315
context = new Context("my-operation-key");
1416

1517
// Attach custom properties
16-
context["prop-1"] = "value-1";
17-
context["prop-2"] = 100;
18+
context[Key1] = "value-1";
19+
context[Key2] = 100;
1820

1921
// Retrieve custom properties
20-
string value1 = (string)context["prop-1"];
21-
int value2 = (int)context["prop-2"];
22+
string value1 = (string)context[Key1];
23+
int value2 = (int)context[Key2];
24+
25+
// Bulk attach
26+
context = new Context("my-operation-key", new Dictionary<string, object>
27+
{
28+
{ Key1 , "value-1" },
29+
{ Key2 , 100 }
30+
});
2231

2332
#endregion
2433
}
@@ -34,12 +43,22 @@ public static void Context_V8()
3443
context = ResilienceContextPool.Shared.Get("my-operation-key");
3544

3645
// Attach custom properties
37-
context.Properties.Set(new ResiliencePropertyKey<string>("prop-1"), "value-1");
38-
context.Properties.Set(new ResiliencePropertyKey<int>("prop-2"), 100);
46+
ResiliencePropertyKey<string> propertyKey1 = new(Key1);
47+
context.Properties.Set(propertyKey1, "value-1");
48+
49+
ResiliencePropertyKey<int> propertyKey2 = new(Key2);
50+
context.Properties.Set(propertyKey2, 100);
51+
52+
// Bulk attach
53+
context.Properties.SetProperties(new Dictionary<string, object?>
54+
{
55+
{ Key1 , "value-1" },
56+
{ Key2 , 100 }
57+
}, out var oldProperties);
3958

4059
// Retrieve custom properties
41-
string value1 = context.Properties.GetValue(new ResiliencePropertyKey<string>("prop-1"), "default");
42-
int value2 = context.Properties.GetValue(new ResiliencePropertyKey<int>("prop-2"), 0);
60+
string value1 = context.Properties.GetValue(propertyKey1, "default");
61+
int value2 = context.Properties.GetValue(propertyKey2, 0);
4362

4463
// Return the context to the pool
4564
ResilienceContextPool.Shared.Return(context);

0 commit comments

Comments
 (0)