Skip to content

Commit

Permalink
[Docs] Make quick start samples consistent (#1735)
Browse files Browse the repository at this point in the history
  • Loading branch information
peter-csala committed Oct 28, 2023
1 parent a0e30b0 commit 56ffa14
Show file tree
Hide file tree
Showing 16 changed files with 468 additions and 427 deletions.
324 changes: 174 additions & 150 deletions README.md

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ ResiliencePipeline pipeline = new ResiliencePipelineBuilder()
.Build(); // Builds the resilience pipeline
// Execute the pipeline asynchronously
await pipeline.ExecuteAsync(static async cancellationToken => { /*Your custom logic here */ }, cancellationToken);
await pipeline.ExecuteAsync(static async token => { /*Your custom logic goes here */ }, cancellationToken);
```
<!-- endSnippet -->

Expand All @@ -46,7 +46,7 @@ services.AddResiliencePipeline("my-pipeline", builder =>
});

// Build the service provider
IServiceProvider serviceProvider = services.BuildServiceProvider();
var serviceProvider = services.BuildServiceProvider();

// Retrieve ResiliencePipelineProvider that caches and dynamically creates the resilience pipelines
var pipelineProvider = serviceProvider.GetRequiredService<ResiliencePipelineProvider<string>>();
Expand All @@ -57,7 +57,7 @@ ResiliencePipeline pipeline = pipelineProvider.GetPipeline("my-pipeline");
// Execute the pipeline
await pipeline.ExecuteAsync(static async token =>
{
// Your custom logic here
// Your custom logic goes here
});
```
<!-- endSnippet -->
44 changes: 24 additions & 20 deletions docs/strategies/circuit-breaker.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,38 +20,38 @@

<!-- snippet: circuit-breaker -->
```cs
// Add circuit breaker with default options.
// Circuit breaker with default options.
// See https://www.pollydocs.org/strategies/circuit-breaker#defaults for defaults.
new ResiliencePipelineBuilder().AddCircuitBreaker(new CircuitBreakerStrategyOptions());
var optionsDefaults = new CircuitBreakerStrategyOptions();

// Add circuit breaker with customized options:
//
// Circuit breaker with customized options:
// The circuit will break if more than 50% of actions result in handled exceptions,
// within any 10-second sampling duration, and at least 8 actions are processed.
new ResiliencePipelineBuilder().AddCircuitBreaker(new CircuitBreakerStrategyOptions
var optionsComplex = new CircuitBreakerStrategyOptions
{
FailureRatio = 0.5,
SamplingDuration = TimeSpan.FromSeconds(10),
MinimumThroughput = 8,
BreakDuration = TimeSpan.FromSeconds(30),
ShouldHandle = new PredicateBuilder().Handle<SomeExceptionType>()
});
};

// Handle specific failed results for HttpResponseMessage:
new ResiliencePipelineBuilder<HttpResponseMessage>()
.AddCircuitBreaker(new CircuitBreakerStrategyOptions<HttpResponseMessage>
{
ShouldHandle = new PredicateBuilder<HttpResponseMessage>()
.Handle<SomeExceptionType>()
.HandleResult(response => response.StatusCode == HttpStatusCode.InternalServerError)
});
var optionsShouldHandle = new CircuitBreakerStrategyOptions<HttpResponseMessage>
{
ShouldHandle = new PredicateBuilder<HttpResponseMessage>()
.Handle<SomeExceptionType>()
.HandleResult(response => response.StatusCode == HttpStatusCode.InternalServerError)
};

// Monitor the circuit state, useful for health reporting:
var stateProvider = new CircuitBreakerStateProvider();
var optionsStateProvider = new CircuitBreakerStrategyOptions<HttpResponseMessage>
{
StateProvider = stateProvider
};

new ResiliencePipelineBuilder<HttpResponseMessage>()
.AddCircuitBreaker(new() { StateProvider = stateProvider })
.Build();
var circuitState = stateProvider.CircuitState;

/*
CircuitState.Closed - Normal operation; actions are executed.
Expand All @@ -62,16 +62,20 @@ CircuitState.Isolated - Circuit is manually held open; actions are blocked.

// Manually control the Circuit Breaker state:
var manualControl = new CircuitBreakerManualControl();

new ResiliencePipelineBuilder()
.AddCircuitBreaker(new() { ManualControl = manualControl })
.Build();
var optionsManualControl = new CircuitBreakerStrategyOptions
{
ManualControl = manualControl
};

// Manually isolate a circuit, e.g., to isolate a downstream service.
await manualControl.IsolateAsync();

// Manually close the circuit to allow actions to be executed again.
await manualControl.CloseAsync();

// Add a circuit breaker strategy with a CircuitBreakerStrategyOptions{<TResult>} instance to the pipeline
new ResiliencePipelineBuilder().AddCircuitBreaker(optionsDefaults);
new ResiliencePipelineBuilder<HttpResponseMessage>().AddCircuitBreaker(optionsStateProvider);
```
<!-- endSnippet -->

Expand Down
72 changes: 36 additions & 36 deletions docs/strategies/fallback.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,48 +12,48 @@

<!-- snippet: fallback -->
```cs
// Add a fallback/substitute value if an operation fails.
new ResiliencePipelineBuilder<UserAvatar>()
.AddFallback(new FallbackStrategyOptions<UserAvatar>
{
ShouldHandle = new PredicateBuilder<UserAvatar>()
.Handle<SomeExceptionType>()
.HandleResult(r => r is null),
FallbackAction = args => Outcome.FromResultAsValueTask(UserAvatar.Blank)
});
// A fallback/substitute value if an operation fails.
var optionsSubstitute = new FallbackStrategyOptions<UserAvatar>
{
ShouldHandle = new PredicateBuilder<UserAvatar>()
.Handle<SomeExceptionType>()
.HandleResult(r => r is null),
FallbackAction = static args => Outcome.FromResultAsValueTask(UserAvatar.Blank)
};

// Use a dynamically generated value if an operation fails.
new ResiliencePipelineBuilder<UserAvatar>()
.AddFallback(new FallbackStrategyOptions<UserAvatar>
var optionsFallbackAction = new FallbackStrategyOptions<UserAvatar>
{
ShouldHandle = new PredicateBuilder<UserAvatar>()
.Handle<SomeExceptionType>()
.HandleResult(r => r is null),
FallbackAction = static args =>
{
ShouldHandle = new PredicateBuilder<UserAvatar>()
.Handle<SomeExceptionType>()
.HandleResult(r => r is null),
FallbackAction = args =>
{
var avatar = UserAvatar.GetRandomAvatar();
return Outcome.FromResultAsValueTask(avatar);
}
});
var avatar = UserAvatar.GetRandomAvatar();
return Outcome.FromResultAsValueTask(avatar);
}
};

// Use a default or dynamically generated value, and execute an additional action if the fallback is triggered.
new ResiliencePipelineBuilder<UserAvatar>()
.AddFallback(new FallbackStrategyOptions<UserAvatar>
var optionsOnFallback = new FallbackStrategyOptions<UserAvatar>
{
ShouldHandle = new PredicateBuilder<UserAvatar>()
.Handle<SomeExceptionType>()
.HandleResult(r => r is null),
FallbackAction = static args =>
{
ShouldHandle = new PredicateBuilder<UserAvatar>()
.Handle<SomeExceptionType>()
.HandleResult(r => r is null),
FallbackAction = args =>
{
var avatar = UserAvatar.GetRandomAvatar();
return Outcome.FromResultAsValueTask(UserAvatar.Blank);
},
OnFallback = args =>
{
// Add extra logic to be executed when the fallback is triggered, such as logging.
return default; // Returns an empty ValueTask
}
});
var avatar = UserAvatar.GetRandomAvatar();
return Outcome.FromResultAsValueTask(UserAvatar.Blank);
},
OnFallback = static args =>
{
// Add extra logic to be executed when the fallback is triggered, such as logging.
return default; // Returns an empty ValueTask
}
};

// Add a fallback strategy with a FallbackStrategyOptions<TResult> instance to the pipeline
new ResiliencePipelineBuilder<UserAvatar>().AddFallback(optionsOnFallback);
```
<!-- endSnippet -->

Expand Down
54 changes: 27 additions & 27 deletions docs/strategies/hedging.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,41 +19,41 @@ This strategy also supports multiple [concurrency modes](#concurrency-modes) for

<!-- snippet: hedging -->
```cs
// Add hedging with default options.
// Hedging with default options.
// See https://www.pollydocs.org/strategies/hedging#defaults for defaults.
new ResiliencePipelineBuilder<HttpResponseMessage>()
.AddHedging(new HedgingStrategyOptions<HttpResponseMessage>());
var optionsDefaults = new HedgingStrategyOptions<HttpResponseMessage>();

// Add a customized hedging strategy that retries up to 3 times if the execution
// A customized hedging strategy that retries up to 3 times if the execution
// takes longer than 1 second or if it fails due to an exception or returns an HTTP 500 Internal Server Error.
new ResiliencePipelineBuilder<HttpResponseMessage>()
.AddHedging(new HedgingStrategyOptions<HttpResponseMessage>
var optionsComplex = new HedgingStrategyOptions<HttpResponseMessage>
{
ShouldHandle = new PredicateBuilder<HttpResponseMessage>()
.Handle<SomeExceptionType>()
.HandleResult(response => response.StatusCode == HttpStatusCode.InternalServerError),
MaxHedgedAttempts = 3,
Delay = TimeSpan.FromSeconds(1),
ActionGenerator = static args =>
{
ShouldHandle = new PredicateBuilder<HttpResponseMessage>()
.Handle<SomeExceptionType>()
.HandleResult(response => response.StatusCode == HttpStatusCode.InternalServerError),
MaxHedgedAttempts = 3,
Delay = TimeSpan.FromSeconds(1),
ActionGenerator = args =>
{
Console.WriteLine("Preparing to execute hedged action.");
Console.WriteLine("Preparing to execute hedged action.");

// Return a delegate function to invoke the original action with the action context.
// Optionally, you can also create a completely new action to be executed.
return () => args.Callback(args.ActionContext);
}
});
// Return a delegate function to invoke the original action with the action context.
// Optionally, you can also create a completely new action to be executed.
return () => args.Callback(args.ActionContext);
}
};

// Subscribe to hedging events.
new ResiliencePipelineBuilder<HttpResponseMessage>()
.AddHedging(new HedgingStrategyOptions<HttpResponseMessage>
var optionsOnHedging = new HedgingStrategyOptions<HttpResponseMessage>
{
OnHedging = static args =>
{
OnHedging = args =>
{
Console.WriteLine($"OnHedging: Attempt number {args.AttemptNumber}");
return default;
}
});
Console.WriteLine($"OnHedging: Attempt number {args.AttemptNumber}");
return default;
}
};

// Add a hedging strategy with a HedgingStrategyOptions<TResult> instance to the pipeline
new ResiliencePipelineBuilder<HttpResponseMessage>().AddHedging(optionsDefaults);
```
<!-- endSnippet -->

Expand Down
11 changes: 6 additions & 5 deletions docs/strategies/rate-limiter.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,12 @@ new ResiliencePipelineBuilder()

// Create a rate limiter that allows 100 executions per minute.
new ResiliencePipelineBuilder()
.AddRateLimiter(new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions
{
PermitLimit = 100,
Window = TimeSpan.FromMinutes(1)
}));
.AddRateLimiter(new SlidingWindowRateLimiter(
new SlidingWindowRateLimiterOptions
{
PermitLimit = 100,
Window = TimeSpan.FromMinutes(1)
}));
```
<!-- endSnippet -->

Expand Down
38 changes: 21 additions & 17 deletions docs/strategies/retry.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,32 +14,32 @@

<!-- snippet: Retry -->
```cs
// Add retry using the default options.
// Retry using the default options.
// See https://www.pollydocs.org/strategies/retry#defaults for defaults.
new ResiliencePipelineBuilder().AddRetry(new RetryStrategyOptions());
var optionsDefaults = new RetryStrategyOptions();

// For instant retries with no delay
new ResiliencePipelineBuilder().AddRetry(new RetryStrategyOptions
var optionsNoDelay = new RetryStrategyOptions
{
Delay = TimeSpan.Zero
});
};

// For advanced control over the retry behavior, including the number of attempts,
// delay between retries, and the types of exceptions to handle.
new ResiliencePipelineBuilder().AddRetry(new RetryStrategyOptions
var optionsComplex = new RetryStrategyOptions
{
ShouldHandle = new PredicateBuilder().Handle<SomeExceptionType>(),
BackoffType = DelayBackoffType.Exponential,
UseJitter = true, // Adds a random factor to the delay
MaxRetryAttempts = 4,
Delay = TimeSpan.FromSeconds(3),
});
};

// To use a custom function to generate the delay for retries
new ResiliencePipelineBuilder().AddRetry(new RetryStrategyOptions
var optionsDelayGenerator = new RetryStrategyOptions
{
MaxRetryAttempts = 2,
DelayGenerator = args =>
DelayGenerator = static args =>
{
var delay = args.AttemptNumber switch
{
Expand All @@ -52,12 +52,12 @@ new ResiliencePipelineBuilder().AddRetry(new RetryStrategyOptions
// but the API also supports asynchronous implementations.
return new ValueTask<TimeSpan?>(delay);
}
});
};

// To extract the delay from the result object
new ResiliencePipelineBuilder<HttpResponseMessage>().AddRetry(new RetryStrategyOptions<HttpResponseMessage>
var optionsExtractDelay = new RetryStrategyOptions<HttpResponseMessage>
{
DelayGenerator = args =>
DelayGenerator = static args =>
{
if (args.Outcome.Result is HttpResponseMessage responseMessage &&
TryGetDelay(responseMessage, out TimeSpan delay))
Expand All @@ -68,26 +68,30 @@ new ResiliencePipelineBuilder<HttpResponseMessage>().AddRetry(new RetryStrategyO
// Returning null means the retry strategy will use its internal delay for this attempt.
return new ValueTask<TimeSpan?>((TimeSpan?)null);
}
});
};

// To get notifications when a retry is performed
new ResiliencePipelineBuilder().AddRetry(new RetryStrategyOptions
var optionsOnRetry = new RetryStrategyOptions
{
MaxRetryAttempts = 2,
OnRetry = args =>
OnRetry = static args =>
{
Console.WriteLine("OnRetry, Attempt: {0}", args.AttemptNumber);

// Event handlers can be asynchronous; here, we return an empty ValueTask.
return default;
}
});
};

// To keep retrying indefinitely or until success use int.MaxValue.
new ResiliencePipelineBuilder().AddRetry(new RetryStrategyOptions
var optionsIndefiniteRetry = new RetryStrategyOptions
{
MaxRetryAttempts = int.MaxValue,
});
};

// Add a retry strategy with a RetryStrategyOptions{<TResult>} instance to the pipeline
new ResiliencePipelineBuilder().AddRetry(optionsDefaults);
new ResiliencePipelineBuilder<HttpResponseMessage>().AddRetry(optionsExtractDelay);
```
<!-- endSnippet -->

Expand Down
Loading

0 comments on commit 56ffa14

Please sign in to comment.