Skip to content

Add circuit breaker configuration support - #483

Open
currantw wants to merge 17 commits into
valkey-io:mainfrom
currantw:474-circuit-breaker
Open

Add circuit breaker configuration support#483
currantw wants to merge 17 commits into
valkey-io:mainfrom
currantw:474-circuit-breaker

Conversation

@currantw

@currantw currantw commented Jul 27, 2026

Copy link
Copy Markdown
Collaborator

Summary

Add CircuitBreakerConfig to the client configuration, matching the existing implementation in Java, Python, Node, and Go (valkey-io/valkey-glide#6050). The circuit breaker logic lives in the Rust core — this task adds the config class, serializes it via FFI, and surfaces the CircuitBreakerException type to callers.

Issue Link

Closes #474.

Features and Behaviour Changes

  • New CircuitBreakerConfig class with fluent WithXxx() API for configuring the client-wide circuit breaker
  • New Errors.CircuitBreakerException thrown when the breaker is open and requests are rejected
  • ConnectionConfiguration builder gains WithCircuitBreaker(CircuitBreakerConfig) method
  • All config properties are optional — unset properties use Rust core defaults

Implementation

  • CircuitBreakerConfig.cs: Sealed class with nullable properties, fluent setters with validation, and ToFfi() conversion
  • Errors.cs: Added CircuitBreakerOpen = 4 to RequestErrorType enum and CircuitBreakerException class
  • FFI.structs.cs: Added CircuitBreakerConfig readonly struct (primary constructor pattern) and wired through ConnectionRequest
  • ConnectionConfiguration.cs: Added field to ConnectionConfig record and builder method
  • rust/src/ffi.rs: Added CircuitBreakerConfig FFI struct and conversion in create_connection_request(). Also simplified existing code with then_some/then/transpose patterns.

Limitations

Testing

  • 23 unit tests (CircuitBreakerConfigTests.cs): defaults, validation, fluent chaining, builder integration
  • 9 integration tests (CircuitBreakerTests.cs):
    • Default/custom config connects successfully (standalone + cluster)
    • Does not interfere with normal operation (aggressive thresholds)
    • No false positives under load (200 sequential commands)
    • Positive test: trips on timeouts and rejects with CircuitBreakerException
  • All tests pass locally

Related Issues

Checklist

  • This Pull Request is related to one issue.
  • Commit message has a detailed description of what changed and why.
  • Tests are added or updated and all checks pass.
  • CHANGELOG.md, README.md, DEVELOPER.md, and other documentation files are updated.
  • Destination branch is correct - main or release
  • Create merge commit if merging release branch into main, squash otherwise.

Add ClientCircuitBreakerConfiguration to the client configuration,
matching the existing implementation in Java, Python, Node, and Go.
The circuit breaker logic lives in the Rust core — this adds the config
class, serializes it via FFI, and surfaces CircuitBreakerException.

- Add CircuitBreakerConfig class with fluent WithXxx() API
- Add CircuitBreakerException mapped from error code 4
- Wire config through FFI structs and Rust create_connection_request()
- Simplify existing FFI code (then_some/transpose patterns)
- Add unit tests for config validation and builder integration
- Add integration tests (normal operation + positive trip test)

Closes valkey-io#474

Signed-off-by: currantw <taylor.curran@improving.com>
Comment thread rust/src/ffi.rs
Signed-off-by: currantw <taylor.curran@improving.com>
@currantw
currantw force-pushed the 474-circuit-breaker branch from 70c6ec7 to 9d874f6 Compare July 27, 2026 20:48
currantw added 2 commits July 27, 2026 14:24
…with ?? default

Remove unnecessary if-blocks and use the same ?? default pattern as all
other optional config fields in the ConnectionRequest initializer.

Signed-off-by: currantw <taylor.curran@improving.com>
… into 474-circuit-breaker

Signed-off-by: currantw <taylor.curran@improving.com>
@currantw
currantw force-pushed the 474-circuit-breaker branch from 33be236 to a4e04a2 Compare July 27, 2026 21:47
currantw added 2 commits July 27, 2026 15:05
Signed-off-by: currantw <taylor.curran@improving.com>
Signed-off-by: currantw <taylor.curran@improving.com>
Comment thread CHANGELOG.md
Comment thread sources/Valkey.Glide/CircuitBreakerConfig.cs Outdated
@currantw currantw self-assigned this Jul 27, 2026
Signed-off-by: currantw <taylor.curran@improving.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds circuit breaker configuration support to the Valkey GLIDE C# client by introducing a public CircuitBreakerConfig API, wiring the configuration through the C#↔Rust FFI boundary, and surfacing a dedicated CircuitBreakerException when the core rejects requests due to an open breaker.

Changes:

  • Introduces CircuitBreakerConfig with fluent WithXxx() setters and FFI serialization.
  • Wires circuit breaker config through ConnectionConfiguration and the FFI ConnectionRequest/Rust ConnectionConfig.
  • Adds Errors.CircuitBreakerException plus unit/integration tests covering config and behavior.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
tests/Valkey.Glide.UnitTests/CircuitBreakerConfigTests.cs Adds unit tests for default/unset behavior and validation of the new config API.
tests/Valkey.Glide.IntegrationTests/CircuitBreakerTests.cs Adds integration tests to validate circuit breaker config doesn’t break connectivity and trips/rejects when expected.
sources/Valkey.Glide/Internals/FFI.structs.cs Extends the marshalled connection request to include circuit breaker config fields and struct layout.
sources/Valkey.Glide/Errors.cs Adds CircuitBreakerException and maps a new RequestErrorType to it.
sources/Valkey.Glide/ConnectionConfiguration.cs Adds builder/property plumbing to attach circuit breaker config to client connection configuration.
sources/Valkey.Glide/CircuitBreakerConfig.cs New public config type with validation, fluent API, and ToFfi() conversion.
rust/src/ffi.rs Adds FFI-side circuit breaker struct and converts it into the core client request.
CHANGELOG.md Documents the new circuit breaker configuration feature in the changelog.
Comments suppressed due to low confidence (2)

sources/Valkey.Glide/CircuitBreakerConfig.cs:74

  • WithFailureRateThreshold currently allows NaN/Infinity because the range checks do not catch those values. Passing NaN through FFI can cause undefined circuit breaker behavior in the core. Reject non-finite values explicitly before the range checks.
        ArgumentOutOfRangeException.ThrowIfLessThanOrEqual(threshold, 0.0, nameof(threshold));
        ArgumentOutOfRangeException.ThrowIfGreaterThan(threshold, 1.0, nameof(threshold));
        FailureRateThreshold = threshold;

sources/Valkey.Glide/CircuitBreakerConfig.cs:100

  • ToFfi() casts OpenTimeout.TotalMilliseconds to uint. For very large timeouts (> ~49.7 days), this overflows and can silently wrap in an unchecked cast. Validate an upper bound when setting the value so the marshalled value stays accurate.
        ArgumentOutOfRangeException.ThrowIfLessThanOrEqual(openTimeout, TimeSpan.Zero, nameof(openTimeout));
        OpenTimeout = openTimeout;

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread sources/Valkey.Glide/ConnectionConfiguration.cs Outdated
Comment thread sources/Valkey.Glide/CircuitBreakerConfig.cs
currantw added 2 commits July 27, 2026 18:11
Signed-off-by: currantw <taylor.curran@improving.com>
@currantw currantw added core Core library (`sources/Valkey.Glide/`) release-1.2 labels Jul 28, 2026
…rowIfNegative

- Add MaxTimeSpan constant to CircuitBreakerConfig; WithWindowSize and
  WithOpenTimeout now reject values exceeding uint.MaxValue ms
- Replace GuardClauses.ThrowIfNegative with
  ArgumentOutOfRangeException.ThrowIfLessThan throughout
- Remove ThrowIfNegative method from GuardClauses
- Update documentation to reflect ArgumentOutOfRangeException
- Add unit tests for overflow cases
- Fix Copilot-reported invalid cref in ConnectionConfiguration.cs

Signed-off-by: currantw <taylor.curran@improving.com>
Signed-off-by: currantw <taylor.curran@improving.com>
@jeremyprime

Copy link
Copy Markdown
Collaborator

As mentioned in comments on the PHP PR I think we should ensure consistency between all the clients, the key pieces being (A) having the CB defaults in the client, and (B) not worrying about config edge case validation (until valkey-io/valkey-glide#5937, although you already have it here so that's fine).

currantw added 2 commits July 30, 2026 09:08
…alidation

- Add public default constants matching glide-core (DefaultWindowSize,
  DefaultFailureRateThreshold, DefaultMinErrors, DefaultOpenTimeout,
  DefaultConsecutiveSuccesses)
- Make MaxTimeSpan public for consumer reference
- Properties are now non-nullable with defaults applied
- Change FailureRateThreshold from double to float (matches FFI type)
- Remove edge-case validation deferred to glide-core (e.g. threshold > 1.0)
- Keep zero/negative guards (FFI sentinels) and MaxTimeSpan upper bound
- Remove integration tests (to be rewritten separately)
- Update unit tests accordingly

Signed-off-by: Taylor Curran <taylor@valkey.io>
Signed-off-by: currantw <taylor.curran@improving.com>
… into 474-circuit-breaker

Signed-off-by: currantw <taylor.curran@improving.com>
@currantw

currantw commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator Author

Made the following changes for consistency with other clients:

  • Added default values in the client
  • Remove unnecessary edge case validation
  • Removed integration tests

However I didn't retain some edge case validation for these two cases:

  • TimeSpan (window size and open timeout). The client validates that these can fit in u32 to avoid overflow.
  • Zero values. Since the Rust core uses zero as a default value for many of these properties, I also validate that these values cannot be set to zero by the user. These aren't valid values, and if we allowed them, the user would get some unexpected results!

Signed-off-by: currantw <taylor.curran@improving.com>
currantw added 3 commits July 30, 2026 11:33
Signed-off-by: currantw <taylor.curran@improving.com>
Signed-off-by: currantw <taylor.curran@improving.com>
Signed-off-by: currantw <taylor.curran@improving.com>
@currantw currantw added this to the 1.2 milestone Jul 31, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

core Core library (`sources/Valkey.Glide/`)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

task(config): Add circuit breaker configuration support

5 participants