Documentation for agents: an index at /llms.txt, every docs page in one file at /llms-full.txt, and Markdown for any docs page by adding .md to its URL.

Effect KitRedis

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");
const sameSlot: boolean
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

reasonCause
cross-slotThe keys of one command or batch hash to different slots.
unresolved-keysThe command's keys cannot be read from its arguments, for example a custom command with dynamic keys.
explicit-target-requiredThe command has no key to route by. Use a ClusterTarget through RedisCluster.
session-routeA command inside a session belongs to another node.
databaseThe 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.