r2d2
Minimal Redis client for Deno.
Features
- Supports RESPv2, RESP3, raw data, pipelining, pub/sub, transactions, eval scripts and Lua scripts.
- Compatible with timeouts and retries.
- The fastest Redis client in Deno. See below and try benchmarking yourself!
- Written to be easily understood and debugged.
- Encourages the use of actual Redis commands without intermediate abstractions.
Usage
Must be run with --allow-net
permission. Check out the full documentation
here.
RESPv2
import { RedisClient } from "https://deno.land/x/r2d2/mod.ts";
const redisConn = await Deno.connect({ port: 6379 });
const redisClient = new RedisClient(redisConn);
// Returns "OK"
await redisClient.sendCommand(["SET", "hello", "world"]);
// Returns "world"
await redisClient.sendCommand(["GET", "hello"]);
If you don’t care about the reply:
import { RedisClient } from "https://deno.land/x/r2d2/mod.ts";
const redisConn = await Deno.connect({ port: 6379 });
const redisClient = new RedisClient(redisConn);
// Returns nothing
await redisClient.writeCommand(["SHUTDOWN"]);
RESP3
import { RedisClient } from "https://deno.land/x/r2d2/mod.ts";
const redisConn = await Deno.connect({ port: 6379 });
const redisClient = new RedisClient(redisConn);
// Switch to RESP3 protocol
await redisClient.sendCommand(["HELLO", 3]);
// Returns 2
await redisClient.sendCommand(["HSET", "hash3", "foo", 1, "bar", 2]);
// Returns { foo: "1", bar: "2" }
await redisClient.sendCommand(["HGETALL", "hash3"]);
Raw data
Set the last argument, raw
, to true
and bulk string replies will return raw
data instead of strings.
import { RedisClient } from "https://deno.land/x/r2d2/mod.ts";
const redisConn = await Deno.connect({ port: 6379 });
const redisClient = new RedisClient(redisConn);
const data = new Uint8Array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
// Returns "OK"
await redisClient.sendCommand(["SET", "binary", data]);
// Returns same value as `data` variable
await redisClient.sendCommand(["GET", "binary"], true);
Pipelining
import { RedisClient } from "https://deno.land/x/r2d2/mod.ts";
const redisConn = await Deno.connect({ port: 6379 });
const redisClient = new RedisClient(redisConn);
// Returns [1, 2, 3, 4]
await redisClient.pipelineCommands([
["INCR", "X"],
["INCR", "X"],
["INCR", "X"],
["INCR", "X"],
]);
Pub/Sub
import { RedisClient } from "https://deno.land/x/r2d2/mod.ts";
const redisConn = await Deno.connect({ port: 6379 });
const redisClient = new RedisClient(redisConn);
await redisClient.writeCommand(["SUBSCRIBE", "mychannel"]);
for await (const reply of redisClient.readReplies()) {
// Prints ["subscribe", "mychannel", 1] first iteration
console.log(reply);
}
Transactions
import { RedisClient } from "https://deno.land/x/r2d2/mod.ts";
const redisConn = await Deno.connect({ port: 6379 });
const redisClient = new RedisClient(redisConn);
// Returns "OK"
await redisClient.sendCommand(["MULTI"]);
// Returns "QUEUED"
await redisClient.sendCommand(["INCR", "FOO"]);
// Returns "QUEUED"
await redisClient.sendCommand(["INCR", "FOO"]);
// Returns [1, 1]
await redisClient.sendCommand(["EXEC"]);
Eval Scripts
import { RedisClient } from "https://deno.land/x/r2d2/mod.ts";
const redisConn = await Deno.connect({ port: 6379 });
const redisClient = new RedisClient(redisConn);
// Returns "hello"
await redisClient.sendCommand(["EVAL", "return ARGV[1]", 0, "hello"]);
Lua Scripts
import { RedisClient } from "https://deno.land/x/r2d2/mod.ts";
const redisConn = await Deno.connect({ port: 6379 });
const redisClient = new RedisClient(redisConn);
// Returns "mylib"
await redisClient.sendCommand([
"FUNCTION",
"LOAD",
"#!lua name=mylib\nredis.register_function('knockknock', function() return 'Who\\'s there?' end)",
]);
// Returns "Who's there?"
await redisClient.sendCommand(["FCALL", "knockknock", 0]);
Timeouts
For further details on deadline()
, see the documentation
here.
import { deadline } from "https://deno.land/std/async/deadline.ts";
import { RedisClient } from "https://deno.land/x/r2d2/mod.ts";
const redisConn = await Deno.connect({ port: 6379 });
const redisClient = new RedisClient(redisConn);
// Rejects if the command takes longer than 100 ms
await deadline(redisClient.sendCommand(["SLOWLOG", "GET"]), 100);
Note: this was added in v0.101.0 of the Deno Standard Library.
Retries
For further details on retry()
, see the documentation
here.
import { retry } from "https://deno.land/std/async/retry.ts";
import { RedisClient } from "https://deno.land/x/r2d2/mod.ts";
// Retries to connect until successful using the exponential backoff algorithm.
const redisConn = await retry(async () => await Deno.connect({ port: 6379 }));
const redisClient = new RedisClient(redisConn);
Note: this was added in v0.167.0 of the Deno Standard Library.
Contributing
Before submitting a pull request, please run deno task ok:dev
. This task
checks formatting, runs the linter and runs tests.
Note: Redis must be installed on your local machine. For installation instructions, see here.
Comparison
Data recorded on October 9, 2023.
Benchmarks
Note: Results were produced using
deno task bench:dev
.
Size
Module | Size (KB) | Dependencies |
---|---|---|
r2d2 | 27.8 | 6 |
deno-redis | 166.49 | 25 |
npm:ioredis | 894.69 | 10 |
npm:redis | 937.16 | 9 |
Note: Results were produced using
deno info <module>