Skip to content

Support custom socket address resolution - #392

Merged
currantw merged 19 commits into
mainfrom
affonsov/address-resolver
May 26, 2026
Merged

Support custom socket address resolution#392
currantw merged 19 commits into
mainfrom
affonsov/address-resolver

Conversation

@affonsov

@affonsov affonsov commented May 12, 2026

Copy link
Copy Markdown
Collaborator

Summary

Ports the custom socket address resolution feature from valkey-glide to the C# client. Allows users to provide a callback that intercepts and rewrites server host/port pairs before the client establishes connections - useful for routing through proxies or custom DNS resolution.

Issue Link

This pull request is linked to issue: N/A (porting from upstream valkey-glide)

Features and Behaviour Changes

  • New public delegate AddressResolverDelegate in ConnectionConfiguration:
    public delegate (string host, ushort port) AddressResolverDelegate(string host, ushort port);
  • New WithAddressResolver() builder method on both StandaloneClientConfigurationBuilder and ClusterClientConfigurationBuilder
  • Feature is fully opt-in - null by default, no behaviour change for existing clients
  • If the resolver throws an exception or returns invalid values (empty host, port 0, oversized hostname), the client falls back to the original address and logs an error (consistent with Java client behavior)

Implementation

Follows the direct FFI callback pattern (same as Go PR valkey-io/valkey-glide#5891), not the socket listener/registry pattern used by Python and Node.

  • Updated valkey-glide submodule to b4b34a1dc16d to include the core Rust AddressResolver trait (PR #5328) and the FFI layer changes (PR #5876)
  • Added AddressResolverCallback C function pointer type and FFIAddressResolver struct to rust/src/lib.rs
  • Updated create_client Rust FFI function with an optional 5th address_resolver parameter
  • C# side marshals the managed delegate to a native function pointer and passes it to the Rust layer; the delegate is held as a field to prevent GC collection

Limitations

  • The resolver is called once per address at connection time; it is not called on reconnection attempts (same behaviour as other language bindings)
  • Maximum resolved hostname length is 1024 bytes

Testing

  • Unit tests in ConnectionConfigurationTests.cs covering builder configuration, defaults, and edge cases
  • Integration tests in AddressResolverTests.cs covering:
    • Identity resolver is invoked and client connects successfully (standalone and cluster)
    • Resolver that throws an exception falls back to original address
    • Resolver returning empty host falls back to original address
    • Resolver returning port zero falls back to original address
    • Resolver returning oversized hostname falls back to original address

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.

@affonsov
affonsov force-pushed the affonsov/address-resolver branch from a426541 to 6ba751a Compare May 12, 2026 01:08
Port PRs valkey-io/valkey-glide#5328, #5876, #5890, #5891 to the C# client.

Adds an optional AddressResolverDelegate callback to the connection
configuration that intercepts and rewrites server host/port pairs before
the client establishes connections. Useful for routing through proxies
or custom DNS resolution.

Implementation follows the direct FFI callback pattern (same as Go),
not the socket listener/registry pattern used by Python and Node.

Changes:
- Update valkey-glide submodule to b4b34a1dc16d (includes core Rust
  infra from #5328 and FFI layer from #5876)
- rust/src/ffi.rs: add address_resolver: None to ConnectionRequest
- rust/src/lib.rs: add AddressResolverCallback type, FFIAddressResolver
  struct implementing redis::AddressResolver, update create_client with
  optional 5th address_resolver parameter
- FFI.methods.cs: add 5th IntPtr addressResolverCallback param to both
  CreateClientFfi declarations
- ConnectionConfiguration.cs: add AddressResolverDelegate public
  delegate, AddressResolver field, WithAddressResolver() builder method
- BaseClient.cs: add AddressResolverAction delegate, _addressResolverDelegate
  field (GC-safe), wire up in CreateClient<T>
- AddressResolverTests.cs: 5 unit tests

Signed-off-by: affonsov <67347924+affonsov@users.noreply.github.com>
@affonsov
affonsov force-pushed the affonsov/address-resolver branch from 6ba751a to 2ff8a4b Compare May 12, 2026 01:51
Comment thread tests/Valkey.Glide.UnitTests/AddressResolverTests.cs Outdated
Comment thread rust/src/lib.rs Outdated
Comment thread sources/Valkey.Glide/ConnectionConfiguration.cs
Comment thread rust/src/lib.rs Outdated
Comment thread rust/src/lib.rs
Comment thread sources/Valkey.Glide/ConnectionConfiguration.cs Outdated
Comment thread sources/Valkey.Glide/Client/BaseClient.cs
Comment thread tests/Valkey.Glide.UnitTests/AddressResolverTests.cs Outdated
Comment thread sources/Valkey.Glide/Client/BaseClient.cs Outdated
Comment thread sources/Valkey.Glide/Client/BaseClient.cs Outdated
Comment thread sources/Valkey.Glide/Client/BaseClient.cs Outdated
@currantw currantw added core Core library (`sources/Valkey.Glide/`) release-1.2 labels May 25, 2026
currantw added 14 commits May 25, 2026 16:34
… into affonsov/address-resolver

Signed-off-by: currantw <taylor.curran@improving.com>
…callback, and refactor adddress resolver tests

Signed-off-by: currantw <taylor.curran@improving.com>
Signed-off-by: currantw <taylor.curran@improving.com>
Signed-off-by: currantw <taylor.curran@improving.com>
Signed-off-by: currantw <taylor.curran@improving.com>
Signed-off-by: currantw <taylor.curran@improving.com>
Signed-off-by: currantw <taylor.curran@improving.com>
Signed-off-by: currantw <taylor.curran@improving.com>
- Wrap user-provided AddressResolver delegate in try/catch to prevent
  process crash if the delegate throws an exception
- Log the exception at Error level for debuggability
- Return 0 to signal failure to Rust, which falls back to the original
  address (consistent with Java client behavior)
- Add integration test verifying fallback behavior when resolver throws

Signed-off-by: currantw <taylor.curran@improving.com>
Signed-off-by: currantw <taylor.curran@improving.com>
…g integration tests.

Signed-off-by: currantw <taylor.curran@improving.com>
Signed-off-by: currantw <taylor.curran@improving.com>
Rust:
- Extract MAX_RESOLVED_HOST_LEN constant (1024 bytes)
- Use stack allocation instead of heap for resolve buffer
- Add full doc comments on AddressResolverCallback matching
  SuccessCallback/FailureCallback style
- Add doc comment on FFIAddressResolver explaining newtype pattern
- Add SAFETY comment on unsafe impl Send + Sync
- Document fallback behavior on resolve() method
- Add address_resolver to create_client safety docs

C#:
- Expand AddressResolverDelegate XML docs (use cases, thread safety,
  error behavior, reconnection note)
- Add <seealso> tag on AddressResolver property
- Extract addressResolver local variable to avoid capturing config.Request
- Add comment on unsafe pointer write (outLen always valid from Rust)
- Add comment explaining why _addressResolverDelegate is not readonly
- Log specific error messages for each failure case (empty host,
  oversized host, invalid port)

Signed-off-by: currantw <taylor.curran@improving.com>
Signed-off-by: currantw <taylor.curran@improving.com>
@currantw currantw assigned currantw and unassigned affonsov May 26, 2026
@currantw currantw changed the title C#: Support custom socket address resolution Support custom socket address resolution May 26, 2026
@currantw
currantw requested a review from alexr-bq May 26, 2026 16:21
Comment thread sources/Valkey.Glide/Client/BaseClient.cs Outdated
currantw added 3 commits May 26, 2026 11:16
Signed-off-by: currantw <taylor.curran@improving.com>
Signed-off-by: currantw <taylor.curran@improving.com>
@currantw
currantw merged commit 7a822d4 into main May 26, 2026
22 of 24 checks passed
@currantw
currantw deleted the affonsov/address-resolver branch May 26, 2026 21:32
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.

4 participants