-
Notifications
You must be signed in to change notification settings - Fork 10
Add circuit breaker configuration support #483
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
17 commits
Select commit
Hold shift + click to select a range
327e520
feat(config): add circuit breaker configuration support
currantw 9d874f6
docs(changelog): add circuit breaker entry for 1.2.0
currantw 55e4663
refactor(ffi): inline ClientSideCacheConfig and CircuitBreakerConfig …
currantw a4e04a2
Merge branch 'main' of https://github.com/valkey-io/valkey-glide-csha…
currantw e35c710
Use nameof in exceptions
currantw 6c12080
Use nameof in exceptions pt. 2
currantw f7ec760
Fix lint
currantw 4345ed6
Fix lint 2.0
currantw a16f902
Merge branch 'main' of https://github.com/valkey-io/valkey-glide-csha…
currantw 6303792
fix(config): validate TimeSpan upper bound and remove GuardClauses.Th…
currantw f2d99ad
Fix unit test failures
currantw b6d429c
refactor(config): add defaults to CircuitBreakerConfig and simplify v…
currantw 681b2a8
Merge branch 'main' of https://github.com/valkey-io/valkey-glide-csha…
currantw f53e308
Fix build errors
currantw 1f53dfc
Fix ArgumentOutOfRangeException
currantw c06bff9
Add ToFFI unit tests
currantw 2452a42
Fix lint error
currantw File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,200 @@ | ||
| // Copyright Valkey GLIDE Project Contributors - SPDX Identifier: Apache-2.0 | ||
|
|
||
| using Valkey.Glide.Internals; | ||
|
|
||
| namespace Valkey.Glide; | ||
|
|
||
| /// <summary> | ||
| /// Configuration for the client-wide circuit breaker. | ||
| /// </summary> | ||
| /// <seealso href="https://glide.valkey.io/how-to/connections/circuit-breaker/">Valkey GLIDE – Configure a Circuit Breaker</seealso> | ||
| public sealed class CircuitBreakerConfig | ||
| { | ||
| #region Constants | ||
|
|
||
| /// <summary> | ||
| /// TimeSpan parameters are marshalled to the Rust core as <c>u32</c> milliseconds, | ||
| /// so values exceeding this limit will throw an exception during configuration. | ||
| /// </summary> | ||
| public static readonly TimeSpan MaxTimeSpan = TimeSpan.FromMilliseconds(uint.MaxValue); | ||
|
|
||
| /// <summary> | ||
| /// Default sliding window duration for error rate calculation (10 seconds). | ||
| /// </summary> | ||
| public static readonly TimeSpan DefaultWindowSize = TimeSpan.FromSeconds(10); | ||
|
|
||
| /// <summary> | ||
| /// Default failure rate threshold within the window to trip the breaker (50%). | ||
| /// </summary> | ||
| public const float DefaultFailureRateThreshold = 0.5f; | ||
|
|
||
| /// <summary> | ||
| /// Default minimum number of errors within the window before the rate is evaluated (50). | ||
| /// </summary> | ||
| public const uint DefaultMinErrors = 50; | ||
|
|
||
| /// <summary> | ||
| /// Default time in Open state before allowing a probe request (5 seconds). | ||
| /// </summary> | ||
| public static readonly TimeSpan DefaultOpenTimeout = TimeSpan.FromSeconds(5); | ||
|
|
||
| /// <summary> | ||
| /// Default number of consecutive successful probe requests needed before closing the breaker (3). | ||
| /// </summary> | ||
| public const uint DefaultConsecutiveSuccesses = 3; | ||
|
|
||
| #endregion | ||
| #region Public Properties | ||
|
|
||
| /// <summary> | ||
| /// Sliding window duration for error rate calculation. | ||
| /// </summary> | ||
| public TimeSpan WindowSize { get; private set; } = DefaultWindowSize; | ||
|
|
||
| /// <summary> | ||
| /// Failure rate threshold (0.0, 1.0] within the window to trip the breaker. | ||
| /// </summary> | ||
| public float FailureRateThreshold { get; private set; } = DefaultFailureRateThreshold; | ||
|
|
||
| /// <summary> | ||
| /// Minimum number of errors within the window before the rate is evaluated. | ||
| /// Prevents tripping on small sample sizes. | ||
| /// </summary> | ||
| public uint MinErrors { get; private set; } = DefaultMinErrors; | ||
|
|
||
| /// <summary> | ||
| /// Time in Open state before allowing a probe request. | ||
| /// </summary> | ||
| public TimeSpan OpenTimeout { get; private set; } = DefaultOpenTimeout; | ||
|
|
||
| /// <summary> | ||
| /// Whether command timeouts count toward tripping the breaker. Set to true only if | ||
| /// timeouts reliably indicate server-side issues rather than client-side thread pool starvation. | ||
| /// </summary> | ||
| public bool CountTimeouts { get; private set; } = false; | ||
|
|
||
| /// <summary> | ||
| /// Number of consecutive successful probe requests needed before closing the breaker. | ||
| /// Provides a grace period to prevent flapping. | ||
| /// </summary> | ||
| public uint ConsecutiveSuccesses { get; private set; } = DefaultConsecutiveSuccesses; | ||
|
|
||
| #endregion | ||
| #region Public Methods | ||
|
|
||
| /// <summary> | ||
| /// Sets the sliding window duration for error rate calculation. | ||
| /// </summary> | ||
| /// <param name="windowSize">The window size.</param> | ||
| /// <returns>This instance for method chaining.</returns> | ||
| /// <exception cref="ArgumentOutOfRangeException"> | ||
| /// Thrown if <paramref name="windowSize"/> is not positive or exceeds <see cref="MaxTimeSpan"/>. | ||
| /// </exception> | ||
| public CircuitBreakerConfig WithWindowSize(TimeSpan windowSize) | ||
| { | ||
| ArgumentOutOfRangeException.ThrowIfLessThanOrEqual(windowSize, TimeSpan.Zero, nameof(windowSize)); | ||
| ArgumentOutOfRangeException.ThrowIfGreaterThan(windowSize, MaxTimeSpan, nameof(windowSize)); | ||
|
|
||
| WindowSize = windowSize; | ||
| return this; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Sets the error rate threshold (0.0, 1.0] within the window to trip the breaker. | ||
| /// </summary> | ||
| /// <param name="threshold">The threshold value.</param> | ||
| /// <returns>This instance for method chaining.</returns> | ||
| /// <exception cref="ArgumentOutOfRangeException"> | ||
| /// Thrown when <paramref name="threshold"/> is zero or negative. | ||
| /// </exception> | ||
| public CircuitBreakerConfig WithFailureRateThreshold(float threshold) | ||
| { | ||
| ArgumentOutOfRangeException.ThrowIfLessThanOrEqual(threshold, 0.0f, nameof(threshold)); | ||
|
|
||
| FailureRateThreshold = threshold; | ||
| return this; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Sets the minimum number of errors within the window before the rate is evaluated. | ||
| /// </summary> | ||
| /// <param name="minErrors">The minimum error count.</param> | ||
| /// <returns>This instance for method chaining.</returns> | ||
| /// <exception cref="ArgumentOutOfRangeException"> | ||
| /// Thrown when <paramref name="minErrors"/> is zero. | ||
| /// </exception> | ||
| public CircuitBreakerConfig WithMinErrors(uint minErrors) | ||
| { | ||
| ArgumentOutOfRangeException.ThrowIfLessThanOrEqual(minErrors, 0u, nameof(minErrors)); | ||
|
|
||
| MinErrors = minErrors; | ||
| return this; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Sets the time in Open state before allowing a probe request. | ||
| /// </summary> | ||
| /// <param name="openTimeout">The open timeout duration.</param> | ||
| /// <returns>This instance for method chaining.</returns> | ||
| /// <exception cref="ArgumentOutOfRangeException"> | ||
| /// Thrown if <paramref name="openTimeout"/> is not positive or exceeds <see cref="MaxTimeSpan"/>. | ||
| /// </exception> | ||
| public CircuitBreakerConfig WithOpenTimeout(TimeSpan openTimeout) | ||
| { | ||
| ArgumentOutOfRangeException.ThrowIfLessThanOrEqual(openTimeout, TimeSpan.Zero, nameof(openTimeout)); | ||
| ArgumentOutOfRangeException.ThrowIfGreaterThan(openTimeout, MaxTimeSpan, nameof(openTimeout)); | ||
|
|
||
| OpenTimeout = openTimeout; | ||
| return this; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Sets whether command timeouts count toward tripping the breaker. | ||
| /// </summary> | ||
| /// <param name="countTimeouts">Whether to count timeouts.</param> | ||
| /// <returns>This instance for method chaining.</returns> | ||
| public CircuitBreakerConfig WithCountTimeouts(bool countTimeouts = true) | ||
| { | ||
| CountTimeouts = countTimeouts; | ||
| return this; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Sets the number of consecutive successful probe requests needed before closing the breaker. | ||
| /// </summary> | ||
| /// <param name="consecutiveSuccesses">The number of successes.</param> | ||
| /// <returns>This instance for method chaining.</returns> | ||
| /// <exception cref="ArgumentOutOfRangeException"> | ||
| /// Thrown when <paramref name="consecutiveSuccesses"/> is zero. | ||
| /// </exception> | ||
| public CircuitBreakerConfig WithConsecutiveSuccesses(uint consecutiveSuccesses) | ||
| { | ||
| ArgumentOutOfRangeException.ThrowIfLessThanOrEqual(consecutiveSuccesses, 0u, nameof(consecutiveSuccesses)); | ||
|
|
||
| ConsecutiveSuccesses = consecutiveSuccesses; | ||
| return this; | ||
| } | ||
|
|
||
| #endregion | ||
| #region Internal Methods | ||
|
|
||
| /// <summary> | ||
| /// Converts to the FFI representation for marshalling to Rust core. | ||
| /// </summary> | ||
| internal FFI.CircuitBreakerConfig ToFfi() | ||
| { | ||
| // Casts to uint are safe: validated by WithWindowSize and WithOpenTimeout. | ||
| var windowSize = (uint)WindowSize.TotalMilliseconds; | ||
| var openTimeout = (uint)OpenTimeout.TotalMilliseconds; | ||
|
|
||
| return new( | ||
| windowSize, | ||
| FailureRateThreshold, | ||
| MinErrors, | ||
| openTimeout, | ||
| CountTimeouts, | ||
| ConsecutiveSuccesses); | ||
| } | ||
|
|
||
| #endregion | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.