Skip to content

feat: try every address a contact point resolves to (DRIVER-201) - #1074

Draft
nikagra wants to merge 3 commits into
scylladb:scylla-4.xfrom
nikagra:s2/07-expand-contact-points
Draft

nikagra wants to merge 3 commits into
scylladb:scylla-4.xfrom
nikagra:s2/07-expand-contact-points

Conversation

@nikagra

@nikagra nikagra commented Sep 9, 2026

Copy link
Copy Markdown

A contact point given as a hostname was one connection attempt, to whatever address Netty's resolver returned first: a dead first record failed CqlSession.build() (DRIVER-201), and the reconnection fallback from #1065 re-tried one address per round.

  • When the control connection reaches an unresolved contact point, at startup or through the fallback, the name is resolved to all of its addresses (ChannelFactory.resolveAll, feat: add resolveAll through Netty's configured resolver (DRIVER-201) #1073), deduplicated, shuffled and capped at the new advanced.connection.max-candidate-addresses (default 5); each address is tried as its own temporary node named cluster.example.com/10.0.0.1:9042, ahead of the rest of the plan.
  • AllNodesFailedException carries one entry per address; TLS and authentication keep seeing the configured name.
  • Nothing else expands: IP literals, resolved contact points, custom EndPoints and identified nodes are tried as before. A resolver failure or an unusable answer falls back to today's single connect.
  • The node reached through a contact point is registered under the labelled address (resolve() resolved, toString()/node tag gain /ip, prefix, TLS and auth name unchanged; its pool stops re-resolving the name). That is the labelled form of 4.x: the node reached through a contact-point hostname is registered under that hostname, which can later resolve to another node #1072, documented in the upgrade guide.

Verified: ControlConnectionTest +14 (8 red against the pre-expansion code, 6 pin unchanged paths), full core suite (3997) green on JDK 11, docs build; MockResolverIT against ScyllaDB 2026.1.9 including the dead-first-record case. Not covered locally: the Cassandra CCM lanes.

Stacked on #1073 (s2/06-resolve-all), which sits on scylla-4.x now that #1065 has merged.

Fixes #356
Fixes #989
Fixes #1072
Refs: #890

🤖 Generated with Claude Code

@coderabbitai

coderabbitai Bot commented Sep 9, 2026

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@nikagra
nikagra force-pushed the s2/07-expand-contact-points branch from 650e41c to aee0480 Compare September 9, 2026 22:12
@nikagra
nikagra force-pushed the s2/07-expand-contact-points branch 3 times, most recently from 5d325b7 to 9dd3b25 Compare September 10, 2026 23:03
ChannelFactory.resolveAll(SocketAddress) asks the resolver the driver's
bootstrap would use for a connect, so a custom AddressResolverGroup
installed through NettyOptions.afterBootstrapInitialized is honoured,
for every address a name currently maps to. It mirrors Netty's own
short-circuits (disabled resolver, unsupported or already-resolved
address: the input as is). AddressResolver#resolveAll resolves inline,
so the lookup runs on one pinned I/O loop, never on the caller; the
hook is asked once. No caller yet: the contact-point expansion follows.

Refs: scylladb#890

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
nikagra and others added 2 commits September 14, 2026 23:13
…ER-201)

Two review findings, both about guarantees this commit claims.

Initialise the resolver group and the pinned loop together, once, behind
one lock: two concurrent first calls could each run the bootstrap hook
and pin a loop of their own.

Fail a lookup whose event loop terminates under it. An asynchronous
resolver completes its promise from a response or from a scheduled
timeout, and shutdown cancels the latter without running it, so the
stage stayed pending for good. The listener goes on after the task is
accepted, and comes off when the stage completes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A contact point given as a hostname was one connect: whatever address
Netty's resolver returned first. A dead first record failed build(),
and the fallback re-tried one address per round. When the control
connection reaches such a contact point it now resolves the name to all
its addresses (ChannelFactory.resolveAll), shuffles them, caps them at
advanced.connection.max-candidate-addresses and tries each as its own
temporary node labelled hostname/ip:port, so AllNodesFailedException
names every address. The node reached is registered under that address.

Fixes scylladb#989
Fixes scylladb#1072
Refs: scylladb#890

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@nikagra
nikagra force-pushed the s2/07-expand-contact-points branch from 1f01876 to dc69c16 Compare September 14, 2026 21:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant