Skip to content

feat: shuffle the bulk connect order per connection, not per factory - #65

Merged
lesnik512 merged 1 commit into
mainfrom
feat/shuffle-per-connect
Oct 4, 2026
Merged

lesnik512 merged 1 commit into
mainfrom
feat/shuffle-per-connect

Conversation

@lesnik512

Copy link
Copy Markdown
Member

Closes #35.

Before this change, build_connection_plan shuffled the hosts once, when the factory was built. Every connection the factory opened then sent that same order to asyncpg for its first attempt. asyncpg tries hosts in list order and keeps the first one that matches target_session_attrs. With prefer-standby and two or more standbys, the first standby in a process's order got every connection that process opened.

Now each connect picks a fresh random order for the first attempt across all hosts, and the failover pass keeps its own fresh shuffle on each call, as before.

Shape change

ConnectionPlan no longer holds anything random, so building a plan from the same URL always gives an equal value:

  • primary_host / primary_port are removed.
  • For a multi-host DSN, failover holds the (host, port) pairs in DSN order, and host/port are taken out of connect_args.
  • For a single host, connect_args keeps the host/port the dialect produced. The call to asyncpg gets exactly the same arguments as before.

ConnectionPlan isn't exported, so this doesn't change the public API.

The Primary host entry in CONTEXT.md now says the order is shuffled per connection, not stored on the plan.

One side effect

A DSN with no host at all (postgresql+asyncpg://u:p@/db) used to fail inside build_connection_factory with KeyError: 'host'. Now it is passed through, and asyncpg uses its usual defaults (PGHOST, then the local socket). This matches what is_dsn_multihost already did with that DSN.

Testing

  • New tests that fail on main:
    • build_connection_plan is deterministic, and keeps failover in DSN order.
    • Two connects from one factory send different bulk orders. Randomness is fixed with random.Random(0).
    • Updated assertions on the plan's fields.
  • The pairing invariant test now checks the arguments that actually reach asyncpg.connect, for both the bulk order and every failover attempt.
  • I ran the full suite against Postgres 18 locally, three times: 47 passed, 100% coverage. ruff, ty and eof-fixer are clean.

@lesnik512
lesnik512 merged commit 4178af4 into main Oct 4, 2026
12 checks passed
@lesnik512
lesnik512 deleted the feat/shuffle-per-connect branch October 4, 2026 09:36
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.

The bulk connect order is shuffled once per factory, not once per connection

1 participant