Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .github/workflows/main.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,21 @@ jobs:
--health-interval 10s
--health-timeout 5s
--health-retries 5
redis:
image: redis:8
ports:
- 6379:6379
options: >-
--health-cmd "redis-cli ping"
--health-interval 10s
--health-timeout 5s
--health-retries 5
permissions:
checks: write
pull-requests: write
env:
POSTGRES_URL: postgres://postgres:postgres@localhost:5432/botkit_test
REDIS_URL: redis://localhost:6379/0
steps:
- uses: actions/checkout@v4
- uses: jdx/mise-action@v4
Expand Down
12 changes: 12 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,18 @@ To be released.
- Upgraded Fedify to 2.3.1, LogTape to 2.2.3, and Postgres.js to
3.4.9.

### @fedify/botkit-redis

- Added the new *@fedify/botkit-redis* package, which provides
`RedisRepository`, a Redis-backed implementation of BotKit's
`Repository` interface for bots running on Deno or Node.js. It supports
URL-managed and caller-managed Redis clients, configurable key prefixes,
bot-scoped storage, quote authorization storage, reverse lookups, and
poll votes. [[#12], [#35]]

[#12]: https://github.com/fedify-dev/botkit/issues/12
[#35]: https://github.com/fedify-dev/botkit/pull/35


Version 0.4.4
-------------
Expand Down
61 changes: 61 additions & 0 deletions deno.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions docs/.vitepress/config.mts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ const references = {
text: "@fedify/botkit-postgres",
link: "https://jsr.io/@fedify/botkit-postgres/doc",
},
{
text: "@fedify/botkit-redis",
link: "https://jsr.io/@fedify/botkit-redis/doc",
},
{
text: "@fedify/botkit-sqlite",
link: "https://jsr.io/@fedify/botkit-sqlite/doc",
Expand Down
72 changes: 72 additions & 0 deletions docs/concepts/repository.md
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,78 @@ properties:
[`node:sqlite`]: https://nodejs.org/api/sqlite.html


`RedisRepository`
-----------------

*This API is available since BotKit 0.5.0.*

The `RedisRepository` is a repository that stores data in [Redis] using
the [node-redis] client. It is suited for deployments where multiple bot
processes need to share the same repository state, or where you already
operate Redis for other BotKit infrastructure.

Unlike [`KvRepository`](#kvrepository), `RedisRepository` stores BotKit data
directly in Redis data structures such as strings, sets, and sorted sets.
It supports either an internally owned Redis client created from a connection
URL or an injected client whose lifecycle stays under your control.

In order to use `RedisRepository`, you need to install the
*@fedify/botkit-redis* package:

::: code-group

~~~~ sh [Deno]
deno add jsr:@fedify/botkit-redis
~~~~

~~~~ sh [npm]
npm add @fedify/botkit-redis
~~~~

~~~~ sh [pnpm]
pnpm add @fedify/botkit-redis
~~~~

~~~~ sh [Yarn]
yarn add @fedify/botkit-redis
~~~~

:::

The `RedisRepository` constructor accepts the following properties:

`url`
: A Redis connection string used to create an internal client. Exactly one
of `url` and `client` must be provided.

`client`
: An existing node-redis compatible client. When this is provided, the
repository does not own the client and calling `close()` will not shut it
down.

`prefix` (optional)
: The Redis key prefix used for BotKit data. Defaults to `"botkit"`.

`clientOptions` (optional)
: Additional node-redis client options. This option is only valid when
`url` is used.

`lockTimeoutMs` (optional)
: How long a Redis lock can live without renewal, in milliseconds.
Defaults to `30000`.

`lockPollIntervalMs` (optional)
: How long to wait before retrying a held Redis lock, in milliseconds.
Defaults to `20`.

`lockRenewIntervalMs` (optional)
: How often to renew a held Redis lock, in milliseconds. Defaults to
`10000`.

[Redis]: https://redis.io/
[node-redis]: https://github.com/redis/node-redis


`PostgresRepository`
--------------------

Expand Down
2 changes: 2 additions & 0 deletions docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"devDependencies": {
"@fedify/botkit": "workspace:",
"@fedify/botkit-postgres": "workspace:",
"@fedify/botkit-redis": "workspace:",
"@fedify/botkit-sqlite": "workspace:",
"@fedify/denokv": "jsr:@fedify/denokv@^2.3.1",
"@fedify/fedify": "catalog:",
Expand All @@ -19,6 +20,7 @@
"markdown-it-footnote": "^4.0.0",
"markdown-it-jsr-ref": "^0.5.0",
"postgres": "^3.4.9",
"redis": "^6.1.0",
"srvx": "^0.11.20",
"typescript": "^5.8.3",
"vitepress": "^2.0.0-alpha.17",
Expand Down
15 changes: 15 additions & 0 deletions mise.toml
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,21 @@ outputs = [
]
run = "pnpm --filter @fedify/botkit-postgres run build"

[tasks."build:botkit-redis"]
description = "Build @fedify/botkit-redis"
depends = ["build:botkit"]
sources = [
"packages/botkit-redis/deno.json",
"packages/botkit-redis/package.json",
"packages/botkit-redis/tsdown.config.ts",
"packages/botkit-redis/src/**/*",
]
outputs = [
"packages/botkit-redis/dist/mod.js",
"packages/botkit-redis/dist/mod.d.ts",
]
run = "pnpm --filter @fedify/botkit-redis run build"

[tasks."test:node"]
description = "Build packages and run Node.js tests"
depends = ["build:*"]
Expand Down
115 changes: 115 additions & 0 deletions packages/botkit-redis/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
@fedify/botkit-redis
====================

[![JSR][JSR badge]][JSR]
[![npm][npm badge]][npm]
[![GitHub Actions][GitHub Actions badge]][GitHub Actions]

This package is a [Redis]-based repository implementation for [BotKit]. It
provides shared persistent storage for bots running on either [Deno] or
[Node.js], using Redis data structures for BotKit repository data.

[JSR badge]: https://jsr.io/badges/@fedify/botkit-redis
[JSR]: https://jsr.io/@fedify/botkit-redis
[npm badge]: https://img.shields.io/npm/v/@fedify/botkit-redis?logo=npm
[npm]: https://www.npmjs.com/package/@fedify/botkit-redis
[GitHub Actions badge]: https://github.com/fedify-dev/botkit/actions/workflows/main.yaml/badge.svg
[GitHub Actions]: https://github.com/fedify-dev/botkit/actions/workflows/main.yaml
[Redis]: https://redis.io/
[BotKit]: https://botkit.fedify.dev/
[Deno]: https://deno.land/
[Node.js]: https://nodejs.org/


Installation
------------

~~~~ sh
deno add jsr:@fedify/botkit-redis
npm add @fedify/botkit-redis
pnpm add @fedify/botkit-redis
yarn add @fedify/botkit-redis
~~~~


Usage
-----

The `RedisRepository` can be used as a drop-in repository implementation for
BotKit:

~~~~ typescript
import { createBot, MemoryKvStore } from "@fedify/botkit";
import { RedisRepository } from "@fedify/botkit-redis";

const bot = createBot({
username: "mybot",
kv: new MemoryKvStore(),
repository: new RedisRepository({
url: "redis://localhost:6379/0",
prefix: "botkit",
}),
});
~~~~

You can also inject an existing node-redis client. In that case the
repository does not own the client and `close()` will not shut it down:

~~~~ typescript
import { RedisRepository } from "@fedify/botkit-redis";
import { createClient } from "redis";

const client = createClient({ url: "redis://localhost:6379/0" });
await client.connect();

const repository = new RedisRepository({
client,
prefix: "botkit",
});
~~~~


Options
-------

The `RedisRepository` constructor accepts the following options:

- **`url`**: A Redis connection string for an internally managed client.

- **`client`**: An existing node-redis compatible client to use.

- **`prefix`** (optional): Redis key prefix used for BotKit data. Defaults
to `"botkit"`.

- **`clientOptions`** (optional): Additional node-redis client options.
This option is only valid together with `url`.

- **`lockTimeoutMs`** (optional): How long a Redis lock can live without
renewal, in milliseconds. Defaults to `30000`.

- **`lockPollIntervalMs`** (optional): How long to wait before retrying a
held Redis lock, in milliseconds. Defaults to `20`.

- **`lockRenewIntervalMs`** (optional): How often to renew a held Redis lock,
in milliseconds. Defaults to `10000`.

The options are mutually exclusive: use either `client` or `url`.


Features
--------

- **Cross-runtime**: Works with both Deno and Node.js using node-redis.

- **Shared persistent storage**: Suitable for multi-process deployments
backed by Redis.

- **Key namespacing**: Keeps BotKit data under a configurable Redis prefix.

- **Full `Repository` API**: Implements BotKit repository storage for key
pairs, messages, followers, follows, followees, quote authorizations, and
poll votes.

- **Explicit resource ownership**: Repositories created from a URL own their
Redis client, while repositories created from an injected client leave
lifecycle control to the caller.
Loading
Loading