Skip to content

Implement MultiSubnetFailover - #378

Open
srkaj wants to merge 4 commits into
tiberius-rs:mainfrom
srkaj:multi-subnet-failover
Open

srkaj wants to merge 4 commits into
tiberius-rs:mainfrom
srkaj:multi-subnet-failover

Conversation

@srkaj

@srkaj srkaj commented Apr 11, 2025

Copy link
Copy Markdown

This builds on PR #357 to fix #337.

  • MultiSubnetFailover is a recongnized configuration flag.
  • ... with a public getter in Config.
  • The SqlBrowser implementations (tokio, smol, and async-std) handles multi-subnet failover correctly.
  • Note: When the actual network connection is done by some other crate, that crate must handle multi-subnet failover when creating the socket. See Implement multi-subnet-failover. kardeiz/bb8-tiberius#27 .

@srkaj srkaj changed the title Multi subnet failover Implement MultiSubnetFailover Apr 11, 2025
tylerclendenin and others added 3 commits April 11, 2025 15:04
When the MultiSubnetFailover=Yes property is added to the connection string, the TCP connection should be attempted for each resolved IP address in parallel rather than in sequence. This creates a race where the first connection to be established wins and becomes the target server.

https://learn.microsoft.com/en-us/sql/relational-databases/native-client/features/sql-server-native-client-support-for-high-availability-disaster-recovery?view=sql-server-ver15#connecting-with-multisubnetfailover
@srkaj
srkaj force-pushed the multi-subnet-failover branch from 36c051a to 2732e81 Compare April 11, 2025 13:05
Now better implemented in sql_brower with tokio, async_std and smol.
@srkaj
srkaj force-pushed the multi-subnet-failover branch from 2732e81 to 0d1660f Compare April 11, 2025 13:16
joelparkerhenderson added a commit to mssql-rust/mssql-rust that referenced this pull request Aug 29, 2026
…ects

Mirrors tiberius-rs/tiberius#378.

Adds `Config::multi_subnet_failover`/`Config::get_multi_subnet_failover`
(also parsed from the `MultiSubnetFailover`/`multiSubnetFailover` ADO.NET
and JDBC connection-string property, mirroring the existing `readonly`/
`ApplicationIntent` parsing pattern). When enabled, `SqlBrowser::
connect_named` (all three backends: tokio, async-std, smol) races a
connection attempt against every one of the resolved addresses
concurrently via `FuturesUnordered`, returning as soon as any succeeds,
instead of trying them one at a time. This targets SQL Server Always On
availability group listeners, whose DNS name can resolve to addresses on
multiple subnets where only one is reachable at a time - trying them
sequentially can take as long as the TCP connect timeout per dead
address before reaching the live one.

The per-address connect logic (SSRP/MS-SQLR instance-name resolution +
TCP connect) was factored out into a `connect_addr` helper in each
backend so both the sequential (default) and concurrent
(multi_subnet_failover) branches share one implementation - this mirrors
the existing (non-multi_subnet_failover) control flow exactly for the
default case, just moved into a helper function, so its behavior for
existing callers is unchanged.

`Config::multi_subnet_failover` only affects the `SqlBrowser::
connect_named` code path (used for SQL Server named-instance discovery
via the sql-browser-* features); it has no effect on `Client::connect`,
which takes an already-established `TcpStream` - documented on both.

Added unit tests for the config plumbing (default, explicit set, and
ADO.NET/JDBC connection-string parsing, including an invalid-value
error case). Live testing of the actual connect_named race behavior
would need a real SQL Server Always On listener spanning multiple
subnets (or at minimum a Windows SQL Browser service for the existing
named-instance tests), neither available in this environment - same
gap upstream's PR has (it shipped with no tests at all). The refactor
was verified not to change behavior for the default (non-failover)
path by inspection: the sequential branch is a direct, mechanical
extraction of the pre-existing loop into `connect_addr`, unchanged
statement-for-statement.

Verified:
- cargo check: default, --features=rustls, --features=vendored-openssl,
  --no-default-features, and each of sql-browser-tokio/async-std/smol
- cargo clippy --all-targets -- -D warnings, for default and each
  sql-browser-* feature
- cargo fmt --check
- cargo test --lib (169 passed)
- Live integration tests over rustls (unaffected code paths): 294
  passed (92 bulk + 202 query)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0156Di1tRRLsJK8ctU1AmAJr
joelparkerhenderson added a commit to mssql-rust/mssql-rust that referenced this pull request Aug 30, 2026
…ects

Mirrors tiberius-rs/tiberius#378.

Adds `Config::multi_subnet_failover`/`Config::get_multi_subnet_failover`
(also parsed from the `MultiSubnetFailover`/`multiSubnetFailover` ADO.NET
and JDBC connection-string property, mirroring the existing `readonly`/
`ApplicationIntent` parsing pattern). When enabled, `SqlBrowser::
connect_named` (all three backends: tokio, async-std, smol) races a
connection attempt against every one of the resolved addresses
concurrently via `FuturesUnordered`, returning as soon as any succeeds,
instead of trying them one at a time. This targets SQL Server Always On
availability group listeners, whose DNS name can resolve to addresses on
multiple subnets where only one is reachable at a time - trying them
sequentially can take as long as the TCP connect timeout per dead
address before reaching the live one.

The per-address connect logic (SSRP/MS-SQLR instance-name resolution +
TCP connect) was factored out into a `connect_addr` helper in each
backend so both the sequential (default) and concurrent
(multi_subnet_failover) branches share one implementation - this mirrors
the existing (non-multi_subnet_failover) control flow exactly for the
default case, just moved into a helper function, so its behavior for
existing callers is unchanged.

`Config::multi_subnet_failover` only affects the `SqlBrowser::
connect_named` code path (used for SQL Server named-instance discovery
via the sql-browser-* features); it has no effect on `Client::connect`,
which takes an already-established `TcpStream` - documented on both.

Added unit tests for the config plumbing (default, explicit set, and
ADO.NET/JDBC connection-string parsing, including an invalid-value
error case). Live testing of the actual connect_named race behavior
would need a real SQL Server Always On listener spanning multiple
subnets (or at minimum a Windows SQL Browser service for the existing
named-instance tests), neither available in this environment - same
gap upstream's PR has (it shipped with no tests at all). The refactor
was verified not to change behavior for the default (non-failover)
path by inspection: the sequential branch is a direct, mechanical
extraction of the pre-existing loop into `connect_addr`, unchanged
statement-for-statement.

Verified:
- cargo check: default, --features=rustls, --features=vendored-openssl,
  --no-default-features, and each of sql-browser-tokio/async-std/smol
- cargo clippy --all-targets -- -D warnings, for default and each
  sql-browser-* feature
- cargo fmt --check
- cargo test --lib (169 passed)
- Live integration tests over rustls (unaffected code paths): 294
  passed (92 bulk + 202 query)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0156Di1tRRLsJK8ctU1AmAJr
MattJackson added a commit that referenced this pull request Sep 3, 2026
Integrate upstream PR #378 (resolves #337). Add a `multi_subnet_failover`
option to `Config` with a setter/getter and ADO/JDBC connection-string
parsing of the `MultiSubnetFailover` keyword (via the shared `ConfigString`
trait, so it works for both string formats).

When enabled, the SQL Browser `connect_named` paths (tokio, async-std, smol)
attempt connections to every resolved address in parallel using
`FuturesUnordered` and return the first stream to succeed; otherwise they
fall back to the existing sequential behaviour. The per-address connect
logic is factored into a `connect_addr` helper, and the first observed
error is now preserved instead of being masked by a generic "not found".

Adds unit tests for keyword parsing and end-to-end `from_ado_string`
propagation.
MattJackson added a commit that referenced this pull request Sep 4, 2026
Integrate upstream PR #378 (resolves #337). Add a `multi_subnet_failover`
option to `Config` with a setter/getter and ADO/JDBC connection-string
parsing of the `MultiSubnetFailover` keyword (via the shared `ConfigString`
trait, so it works for both string formats).

When enabled, the SQL Browser `connect_named` paths (tokio, async-std, smol)
attempt connections to every resolved address in parallel using
`FuturesUnordered` and return the first stream to succeed; otherwise they
fall back to the existing sequential behaviour. The per-address connect
logic is factored into a `connect_addr` helper, and the first observed
error is now preserved instead of being masked by a generic "not found".

Adds unit tests for keyword parsing and end-to-end `from_ado_string`
propagation.
MattJackson added a commit that referenced this pull request Sep 6, 2026
Integrate upstream PR #378 (resolves #337). Add a `multi_subnet_failover`
option to `Config` with a setter/getter and ADO/JDBC connection-string
parsing of the `MultiSubnetFailover` keyword (via the shared `ConfigString`
trait, so it works for both string formats).

When enabled, the SQL Browser `connect_named` paths (tokio, async-std, smol)
attempt connections to every resolved address in parallel using
`FuturesUnordered` and return the first stream to succeed; otherwise they
fall back to the existing sequential behaviour. The per-address connect
logic is factored into a `connect_addr` helper, and the first observed
error is now preserved instead of being masked by a generic "not found".

Adds unit tests for keyword parsing and end-to-end `from_ado_string`
propagation.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add Support for MultiSubnetFailover when using a High Availability Group

2 participants