Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

Expose per-attempt connection outcomes with the selected TLS client certificate

Open
#3,252 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
45/100
Issue type
Feature
Clarity
Clearly specified
Activity status
Active
Tech stack
csharp, redis
Domain
api, backend, databases

Research direction

The issue is about modifying the StackExchange.Redis client's connection logic to expose per-attempt outcomes. Start by examining the PhysicalBridge class and its OnConnectionFailed method to understand the current suppression logic. Look for where LocalCertificateSelectionCallback is invoked and how to wrap it to capture the selected certificate. The goal is to design and implement a new callback, ConnectionAttemptCompleted, with the proposed EventArgs, ensuring it fires for all physical connection attempts.

Written by the indexing model from the issue text.

Description

Summary

Please expose a supported, structured callback for every physical connection attempt, including:

  • initial connection attempts;
  • successful reconnects;
  • failed reconnects that do not raise the existing ConnectionFailed event;
  • the client certificate selected for that specific attempt.

The callback should be invoked for both success and failure. This would allow certificate integrations to correlate a connection outcome with the exact certificate used.

The existing ConnectionFailed and ConnectionRestored behavior can remain unchanged for compatibility.

Motivation

We maintain a client-certificate management integration for StackExchange.Redis. It selects a client certificate for each TLS handshake and reports whether that certificate succeeded or failed, allowing fallback to a previously known-good certificate.

In short, I want to provide a client certificate and know if that certificate works.

Two limitations in the current public API prevent reliable integration.

1. Reconnect failures can be suppressed

In StackExchange.Redis, PhysicalBridge.OnConnectionFailed raises ConnectionFailed only while reportNextFailure is true.

After the first failure, the flag remains false until that bridge establishes a connection successfully. Subsequent failed reconnect attempts are therefore not reported through ConnectionFailed.

This creates the following sequence:

  1. Redis is connected successfully.
  2. The established connection closes with SocketClosed.
  3. ConnectionFailed is raised, consuming the bridge's notification.
  4. A newly rotated client certificate is selected for reconnect.
  5. The Redis server rejects that certificate.
  6. The reconnect fails, but no new ConnectionFailed event is raised because connectivity was never restored.
  7. The integration cannot report the rejected certificate or activate its known-good fallback.
  8. Subsequent reconnects continue using the rejected certificate.

A custom failure classifier cannot solve this because it is never invoked when the event itself is suppressed.

2. The selected certificate cannot be correlated with the attempt

LocalCertificateSelectionCallback reports which certificate was selected, while ConnectionFailed and ConnectionRestored report outcomes independently.

The connection outcome does not identify the selected certificate. Integrations must therefore maintain a queue of selected certificates and assume connection outcomes arrive in the same order.

That assumption can fail when interactive and subscription bridges reconnect concurrently or when failures are suppressed.

For example:

  1. Certificate A is selected.
  2. The attempt fails because Redis AUTH credentials are invalid.
  3. Certificate A must be removed from the outstanding-attempt queue without being marked unhealthy.
  4. Multiple bridges and reconnect attempts can interleave selections and outcomes.
  5. Certificate B is later selected and rejected.
  6. Without an outcome carrying the selected certificate, the rejection can be incorrectly attributed to A.

This can produce incorrect fallback decisions, incorrect telemetry, and retained certificate references.

Correlation versus causation

Including the selected certificate would provide deterministic correlation:

Certificate B was selected for the connection attempt that produced exception X.

It would not by itself prove causation:

Certificate B caused exception X.

The same attempt may fail because of:

  • client-certificate rejection;
  • server-certificate validation;
  • Redis authentication;
  • socket connection failure;
  • TLS protocol negotiation;
  • Redis handshake failure.

Including the stage at which the attempt failed would allow integrations to classify the failure without assuming every TLS exception was caused by the client certificate.

Proposed API

Add a configuration-time callback that is invoked for every completed physical connection attempt:

public Action<ConnectionAttemptCompletedEventArgs>?
    ConnectionAttemptCompleted { get; set; }

A configuration-time callback is preferable to an event that can only be attached after Connect returns because it also observes initial connection attempts.

Suggested event arguments:

public sealed class ConnectionAttemptCompletedEventArgs : EventArgs
{
    public EndPoint EndPoint { get; }

    public ConnectionType ConnectionType { get; }

    public string? PhysicalName { get; }

    public X509Certificate? ClientCertificate { get; }

    public bool Succeeded { get; }

    public ConnectionFailureType? FailureType { get; }

    public Exception? Exception { get; }

    public bool? ServerCertificateAccepted { get; }

    public SslPolicyErrors? ServerCertificatePolicyErrors { get; }
}

Capturing the selected certificate

StackExchange.Redis would need to wrap the configured local-certificate selection callback and record the returned certificate on the current physical connection attempt.

This should cover certificate selection configured through both:

  • ConfigurationOptions.CertificateSelection;
  • SslClientAuthenticationOptions.LocalCertificateSelectionCallback.

The captured certificate would then be included in the completion callback for the same attempt.

Optional failure stage information

If practical, the result could also expose the stage at which the attempt failed:

public ConnectionAttemptStage Stage { get; }

public enum ConnectionAttemptStage
{
    SocketConnect,
    TlsAuthentication,
    RedisAuthentication,
    RedisHandshake,
    Established,
}

Example usage

configuration.ConnectionAttemptCompleted = args =>
{
    if (args.ClientCertificateThumbprint is null)
    {
        return;
    }

    if (args.Succeeded)
    {
        // Log that the connection was successful, mark the client certificate as the LKG.
        return;
    }

    if (IsClientCertificateRejection(args))
    {
        // Log that the certificate is not valid, trigger a fallback to LKG if available.
    }
};

Existing alternatives

Currently we utilize a custom ILoggerFactory to detect these errors as it currently receives errors for individual physical failures before ConnectionFailed suppression. However, logging is not an appropriate application-control-flow contract, and correlation with the certificate and stage of authentication (to distinguish between TLS server and client certificate failures) is entirely missing.

Compatibility

The existing ConnectionFailed and ConnectionRestored events should retain their current suppression and notification behavior.

The proposed callback is additive and intended for integrations that require per-attempt outcomes.

Dominant language
C#
Stars
6.2k
Forks
1.6k
Avg merge
1d 15h
Merged PRs (30d)
43

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from StackExchange/StackExchange.Redis

All issues in StackExchange/StackExchange.Redis

Similar issues

More C# issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.