Repository navigation
Description
Motivation
An application already using RedisKvStore should be able to adopt a feature that needs atomic multi-key state without constructing another backend-specific store. The shared contract is useful for general application state as well as delivery suspension and durable backlog. This issue makes the existing @fedify/redis adapter a usable AtomicKvStore in its documented support scope.
Proposed API and use
Implement AtomicKvStore on RedisKvStore. Keep its existing constructor and ordinary KV methods. Add the proposed signatures below, with the supporting entry types defined by the contract issue:
getMany<T = unknown>(keys: readonly KvKey[]): Promise<(T | undefined)[]>;
setMany(entries: readonly KvStoreSetEntry[]): Promise<void>;
deleteMany(keys: readonly KvKey[]): Promise<void>;
casMany(entries: readonly KvStoreCasEntry[]): Promise<boolean>;Keep cas() and make all five methods meet the shared contract. A proposed application use is:
import type { AtomicKvStore } from "@fedify/fedify";
import Redis from "ioredis";
import { RedisKvStore } from "@fedify/redis";
const redis = new Redis(); // Standalone example.
const store: AtomicKvStore = new RedisKvStore(redis);
const keys = [["example", "notice"], ["example", "budget"]] as const;
const [notice, budget] = await store.getMany(keys);
const committed = await store.casMany([
{ key: keys[0], expectedValue: notice, newValue: nextNotice },
{ key: keys[1], expectedValue: budget, newValue: nextBudget },
]);The application computes nextNotice and nextBudget from the snapshot and re-evaluates its rule when the result is false. Connection configuration and client shutdown remain the application's responsibility. These calls are proposed additions, not currently shipped methods.
Backend implementation and choices
Implement real snapshot and conditional-batch semantics for supported Redis modes. Pre-encode values and validate keys, time to live (TTL) and batch limits before mutation. Preserve the codec contract: existing compare-and-swap (CAS) compares encoded bytes, and object property order can affect JSON encoding.
Use an appropriate bounded script or supported transaction strategy; neither pipelining nor the presence of MULTI proves rollback semantics. Redis transaction execution errors do not generally roll back earlier commands. Test the adapter's actual failure paths rather than assuming SQL behavior.
Resolve Redis Cluster atomic scope explicitly. Cluster multi-key operations require the relevant keys to share a slot; existing keys are not automatically placed in one slot. Preserve current single-key CAS and key encoding, and do not silently relocate existing data. If a hash-tag/prefix option or a new scoped key representation is needed, specify collision isolation and migration before implementing it. Cross-slot batches must not degrade to independent operations. Standalone support may ship first if Cluster multi-key support is explicitly excluded and tracked separately; do not list Cluster as a supported atomic configuration until it is verified.
A single global CAS object avoids cross-slot operations at the cost of contention and size, so it is not the default design. Validate a scoped Redis implementation instead.
Shipping criteria
Run the shared Atomic KV conformance suite and the Redis-specific concurrency/failure cases against a supported backend. Verify the package's declared Node, Deno and Bun support, its consumer declarations, and existing KV regression tests. Document unsupported batch scope and limits; do not silently weaken an atomic call or treat method presence as proof of durability.
Revise the RedisKvStore support row and custom-adapter contract in docs/manual/kv.md, packages/redis/README.md, public JSDoc, and relevant KV-selection skill guidance. Add the adapter's changelog fragment. Ship this adapter independently of other backend implementations and of delivery suspension.
Metadata
Metadata
Assignees
Labels
Type
Fields
Priority
Effort
Activity
AtomicKvStore#1363