Skip to content

Commit acdaab8

Browse files
committed
document @commandkit/cache
1 parent 83ed02a commit acdaab8

File tree

1 file changed

+256
-0
lines changed

1 file changed

+256
-0
lines changed
Lines changed: 256 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,259 @@
11
---
22
title: '@commandkit/cache'
33
---
4+
5+
CommandKit provides a powerful caching system that helps you optimize
6+
your bot's performance by storing frequently accessed data in memory.
7+
The `@commandkit/cache` plugin allows you to cache expensive
8+
operations like API calls and database queries, significantly
9+
improving response times and reducing external service usage.
10+
11+
## Installation
12+
13+
Install the cache package to get started:
14+
15+
```bash npm2yarn
16+
npm install @commandkit/cache
17+
```
18+
19+
## Setup
20+
21+
Add the cache plugin to your CommandKit configuration:
22+
23+
```ts title="commandkit.config.ts"
24+
import { defineConfig } from 'commandkit';
25+
import { cache } from '@commandkit/cache';
26+
27+
export default defineConfig({
28+
plugins: [cache()],
29+
});
30+
```
31+
32+
## Basic usage
33+
34+
The simplest way to use caching is with the `"use cache"` directive.
35+
This tells CommandKit to cache the result of your function:
36+
37+
```ts title="src/app/commands/weather.ts"
38+
import type { ChatInputCommand, CommandData } from 'commandkit';
39+
40+
export const command: CommandData = {
41+
name: 'weather',
42+
description: 'Get weather information for a city',
43+
options: [
44+
{
45+
name: 'city',
46+
description: 'The city to get weather for',
47+
type: 3, // String
48+
required: true,
49+
},
50+
],
51+
};
52+
53+
async function fetchWeatherData(city: string) {
54+
'use cache';
55+
56+
// This expensive API call will only run once for each unique city
57+
const response = await fetch(
58+
`https://api.weather.com/v1/current?q=${city}`,
59+
);
60+
return response.json();
61+
}
62+
63+
export const chatInput: ChatInputCommand = async ({
64+
interaction,
65+
}) => {
66+
const city = interaction.options.getString('city', true);
67+
const weather = await fetchWeatherData(city);
68+
69+
await interaction.reply(
70+
`Weather in ${city}: ${weather.description}`,
71+
);
72+
};
73+
```
74+
75+
When you call `fetchWeatherData` multiple times with the same city, it
76+
will only perform the API call once and return the cached result for
77+
subsequent calls.
78+
79+
## How caching works
80+
81+
CommandKit's caching system works by:
82+
83+
1. **Generating a cache key**: Each cached function call generates a
84+
unique key based on the function's identity, arguments, and build
85+
ID
86+
2. **Storing results**: When a function is called, if the result isn't
87+
cached, the function executes and stores its result. If cached, it
88+
returns immediately
89+
3. **Automatic cleanup**: The cache system automatically removes stale
90+
entries and manages memory usage
91+
92+
## Controlling cache behavior
93+
94+
### Setting cache duration
95+
96+
Use `cacheLife` to control how long entries stay in the cache:
97+
98+
```ts
99+
import { cacheLife } from '@commandkit/cache';
100+
101+
async function fetchUserData(userId: string) {
102+
'use cache';
103+
104+
// Cache for 1 hour
105+
cacheLife('1h');
106+
107+
const userData = await db.users.findOne(userId);
108+
return userData;
109+
}
110+
```
111+
112+
Supported time formats:
113+
114+
- `'5s'` - 5 seconds
115+
- `'1m'` - 1 minute
116+
- `'2h'` - 2 hours
117+
- `'1d'` - 1 day
118+
- `60000` - Direct milliseconds
119+
120+
### Using cache tags
121+
122+
Use `cacheTag` to group related cache entries for easier management:
123+
124+
```ts
125+
import { cacheTag } from '@commandkit/cache';
126+
127+
async function fetchGuildSettings(guildId: string) {
128+
'use cache';
129+
130+
// Tag this entry for easy invalidation
131+
cacheTag(`guild:${guildId}`);
132+
cacheTag('settings');
133+
cacheLife('1h');
134+
135+
return await db.guilds.findOne(guildId);
136+
}
137+
```
138+
139+
### Invalidating cache entries
140+
141+
Use `revalidateTag` to invalidate specific cache entries:
142+
143+
```ts
144+
import { revalidateTag } from '@commandkit/cache';
145+
146+
async function updateGuildSettings(guildId: string, settings: any) {
147+
// Update the database
148+
await db.guilds.update(guildId, settings);
149+
150+
// Invalidate all cached guild data
151+
await revalidateTag(`guild:${guildId}`);
152+
}
153+
```
154+
155+
## Common use cases
156+
157+
### Caching API responses
158+
159+
```ts
160+
async function fetchGameStats(gameId: string) {
161+
'use cache';
162+
163+
cacheTag(`game:${gameId}`);
164+
cacheLife('30m'); // API updates every 30 minutes
165+
166+
const response = await fetch(
167+
`https://api.game.com/stats/${gameId}`,
168+
);
169+
return response.json();
170+
}
171+
```
172+
173+
### Caching database queries
174+
175+
```ts
176+
async function getUserProfile(userId: string) {
177+
'use cache';
178+
179+
cacheTag(`user:${userId}`);
180+
cacheLife('1h'); // User profiles don't change often
181+
182+
return await db.users.findOne({
183+
where: { id: userId },
184+
include: ['profile', 'settings'],
185+
});
186+
}
187+
```
188+
189+
### Caching computed results
190+
191+
```ts
192+
async function calculateUserStats(userId: string) {
193+
'use cache';
194+
195+
cacheTag(`user:${userId}`);
196+
cacheTag('stats');
197+
cacheLife('5m'); // Recalculate every 5 minutes
198+
199+
const user = await db.users.findOne(userId);
200+
return {
201+
level: calculateLevel(user.xp),
202+
rank: await calculateRank(userId),
203+
achievements: await getAchievements(userId),
204+
};
205+
}
206+
```
207+
208+
## Advanced configuration
209+
210+
### Custom cache provider
211+
212+
For distributed caching, you can use a custom cache provider like
213+
Redis:
214+
215+
```ts title="commandkit.config.ts"
216+
import { defineConfig } from 'commandkit';
217+
import { cache, setCacheProvider } from '@commandkit/cache';
218+
import { RedisCache } from '@commandkit/redis';
219+
220+
// Set up Redis as the cache provider
221+
setCacheProvider(
222+
new RedisCache({
223+
host: 'localhost',
224+
port: 6379,
225+
}),
226+
);
227+
228+
export default defineConfig({
229+
plugins: [cache()],
230+
});
231+
```
232+
233+
### Manual cache cleanup
234+
235+
Clean up stale cache entries to manage memory usage:
236+
237+
```ts
238+
import { cleanup } from '@commandkit/cache';
239+
240+
// Clean up entries older than 24 hours
241+
await cleanup(24 * 60 * 60 * 1000);
242+
243+
// Set up regular cleanup
244+
setInterval(
245+
async () => {
246+
await cleanup(24 * 60 * 60 * 1000);
247+
},
248+
24 * 60 * 60 * 1000,
249+
); // Run daily
250+
```
251+
252+
:::tip
253+
254+
The `@commandkit/cache` plugin works seamlessly with other CommandKit
255+
features and plugins. You can use it alongside the
256+
[`@commandkit/redis`](./07-commandkit-redis.mdx) plugin for
257+
distributed caching across multiple bot instances.
258+
259+
:::

0 commit comments

Comments
 (0)