Multi-key commands
Keep the keys of one command, pipeline or transaction in the same hash slot with hash tags.
A command that touches several keys works in a cluster only when all of them are in the same hash slot. The client checks this before it sends anything, so a violation fails with ClusterError where reason is "cross-slot" and delivery is "unsent".
Example (A Multi-Key Read That Spans Slots)
import { } from "effect";
import { } from "@effect-kit/redis";
export const = .(function* () {
const = yield* ;
// "foo" and "bar" hash to different slots
return yield* .(["foo", "bar"]);
}).(
.("ClusterError", () =>
. === "cross-slot" ? .("cross-slot") : .(),
),
);Nothing reached a server, so the failure is safe to act on immediately.
Cross-slot fails before sending
The check is in the client. The same keys fail the same way on every call, so retrying does not help. Change the keys.
Using hash tags
A hash tag is the part of a key inside the first { and the first } after it. Only the tag is hashed, so keys that share a tag share a slot.
Example (Keys That Share a Slot)
import { } from "effect";
import { , } from "@effect-kit/redis";
export const = .(function* () {
const = yield* ;
const sameSlot = ("{account:42}:name") === ("{account:42}:visits");
yield* .([
["{account:42}:name", "Ada"],
["{account:42}:visits", "0"],
]);
return { , : yield* .(["{account:42}:name", "{account:42}:visits"]) };
});If a key has an empty tag ({}), the whole key is hashed. Binary keys are hashed as bytes.
Put the tag on whatever the commands have in common, such as an account id. Keys that share a tag live on one node, so a very large tag becomes a hot spot.
Pipelines and transactions
Every keyed command in a pipeline or transaction must be in one slot. The whole batch then runs on the node that owns it.
Example (A Pipeline Within One Slot)
import { , } from "effect";
import { Commands, } from "@effect-kit/redis";
export const = .(function* () {
const = yield* ;
const [, ] = yield* .([
Commands.("{account:42}:name", "Ada"),
Commands.("{account:42}:visits"),
]);
if (.()) return yield* .;
return { , : . };
});A batch that spans slots fails with cross-slot. A batch with no keys, or with a command that has no fixed key or node, fails with explicit-target-required. See Pipelines and Transactions.
Other routing errors
reason | Cause |
|---|---|
cross-slot | The keys of one command or batch hash to different slots. |
unresolved-keys | The command's keys cannot be read from its arguments, for example a custom command with dynamic keys. |
explicit-target-required | The command has no key to route by. Use a ClusterTarget through RedisCluster. |
session-route | A command inside a session belongs to another node. |
database | The command changes database scope (MOVE, SWAPDB), or a non-zero database was requested. |
All of them have delivery: "unsent".
ClusterTarget
Commands without a key need a place to run. RedisCluster takes a ClusterTarget for these: { key } for the node that owns that key, or { node } for a node id. For example, redis.scan() fails with explicit-target-required; see Scanning a cluster.