Skip to content

docs(ruby): correct cluster routing return types in YARD docs - #312

Draft
Aryex wants to merge 2 commits into
mainfrom
alexl/cluster-routing-doc-fixes
Draft

Aryex wants to merge 2 commits into
mainfrom
alexl/cluster-routing-doc-fixes

Conversation

@Aryex

@Aryex Aryex commented Sep 10, 2026

Copy link
Copy Markdown
Collaborator

Summary

Seven route-taking commands documented cluster return shapes that disagree with what glide-core actually returns. This is a docs-only correction — no behavior change.

All cross-node aggregation happens in glide-core (ResponsePolicy::for_command in glide-core/redis-rs/redis/src/cluster_routing.rs); the Ruby client performs none, and every method touched here is a bare send_command pass-through. The bug was purely that the YARD @return tags described the wrong shapes, so users reading the docs would write code against a scalar where a per-node Hash arrives (or vice versa).

Issue link

None — found while auditing Ruby's cluster response handling against the Go, Java, Python and Node clients.

Changes

Corrections in three directions:

Scalar documented, per-node Hash possible@return widened to a union:

Command Before After
bgsave, bgrewriteaof [String] [String, Hash{String => String}]
lastsave [Integer] [Integer, Hash{String => Integer}]
lolwut [String] [String, Hash{String => String}]
function_dump [String] [String, Hash{String => String}]
function_list [Array<Hash>] [Array<Hash>, Hash{String => Array<Hash>}]

BGSAVE / BGREWRITEAOF are the notable ones: they route to all primaries by default with no response policy, so on cluster they return a per-node Hash even with no route: argument, not just under an explicit multi-node route.

Hash documented, never returnedrandomkey claimed "When routed, may return a Hash of node => value". It cannot: RANDOMKEY carries ResponsePolicy::FirstSucceededNonEmptyOrAllEmpty, which always collapses to a single key, or nil when every shard is empty.

Hash over-promisedfunction_stats claimed a Hash keyed by "host:port" unconditionally. FUNCTION STATS is ResponsePolicy::Special with an all-nodes default, so the no-route reply is keyed by node, but a single-node route (e.g. Valkey::Route.random) returns that node's stats unkeyed.

These now match how the peer clients type the same commands: Java ClusterValue<T>, Python TClusterResponse[T], Node ClusterResponse<T>, Go ClusterValue[T]. Commands already documented correctly (dbsize's aggregated sum, ping/flushall/flushdb/config_set/config_resetstat/config_rewrite/save collapsing to a single "OK"/"PONG", and the echo/client_id/time/config_get/info unions) are untouched.

Limitations

Docs only — no runtime behavior, no new tests. Two related gaps found during the audit are deliberately left out of scope:

  • test/integration/cluster/cluster_routing_test.rb asserts only Integer and >= 0 for DBSIZE with all_primaries, so it verifies the collapse but never that the value is genuinely summed. Java, Python and Node all assert the exact total.
  • flatten_map: true flattens every MAP response including the per-node cluster map, which would turn info(route: Route.all_primaries) into a flat Array of unparsed node strings. test/integration/valkey/flatten_map_test.rb is standalone-only, so nothing covers the combination.

Testing

  • bundle exec rubocop on the three changed files — 3 files inspected, no offenses.
  • bundle exec rake test:unit — 352 tests, 631 assertions, 0 failures, 0 errors, 0 skips.

No integration run: the change contains no executable code. Every claim above was verified by reading ResponsePolicy::for_command (cluster_routing.rs:583-636), base_routing (:653-813), the multi-node fold at cluster_async/mod.rs:2324-2512, and the FFI route construction at ffi/src/lib.rs:4646-4664, against mono-repo revision 794486c9a.

Checklist

Before submitting the PR make sure the following are checked:

  • This Pull Request is related to an issue.
  • Commit message describe your changes
  • Commits are signed off (git commit -s) per the DCO.
  • Tests are added or updated.
  • CHANGELOG.md and documentation files are updated.
  • Linters have been run (bundle exec rubocop) and pass.
  • Destination branch is correct - main.

Seven route-taking commands documented return shapes that disagree with
glide-core's response policy (ResponsePolicy::for_command in
glide-core/redis-rs/redis/src/cluster_routing.rs).

- bgsave, bgrewriteaof: default to all primaries with no response policy, so
  the cluster reply is a per-node Hash even with no route; @return said String.
- lastsave, lolwut, function_dump, function_list: a multi-node route yields a
  per-node Hash; @return listed only the scalar.
- randomkey: claimed a per-node Hash, but RANDOMKEY's
  FirstSucceededNonEmptyOrAllEmpty policy always collapses to a single key,
  or nil when every shard is empty.
- function_stats: claimed a Hash keyed by "host:port" unconditionally, but a
  single-node route returns that node's stats unkeyed.

Docs only; no behavior change. All aggregation happens in glide-core, and every
affected method is a bare send_command pass-through. Cross-checked against the
Go, Java, Python and Node clients, which express the same split through
ClusterValue / TClusterResponse / ClusterResponse.

Signed-off-by: Alex Le <alex.le@improving.com>
Signed-off-by: Alex Le <alex.le@improving.com>
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.

1 participant