Redis patterns
Skill ComeOnOliver/skillshub/skills/aiskillstore/marketplace/barnhardt-enterprises-inc/redis-patterns
🧠The right skill, one API call. AI agent skills registry with token-efficient skill resolution. 5,000+ skills from 500+ top repos.
npx -y skills add ComeOnOliver/skillshub --skill redis-patternsAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
What its author says it does
Copied from the file, not written here
Upstash Redis patterns for caching and rate limiting.
SKILL.md
3.5 KB, as published. Nobody here has run it
Upstash Redis Patterns
Setup
// lib/redis.ts
import { Redis } from '@upstash/redis';
export const redis = new Redis({
url: process.env.UPSTASH_REDIS_REST_URL!,
token: process.env.UPSTASH_REDIS_REST_TOKEN!,
});
Basic Caching
// Cache with TTL
async function getCachedUser(id: string): Promise<User | null> {
const cacheKey = `user:${id}`;
// Try cache first
const cached = await redis.get<User>(cacheKey);
if (cached) return cached;
// Fetch from DB
const user = await db.query.users.findFirst({
where: eq(users.id, id),
});
if (user) {
// Cache for 5 minutes
await redis.setex(cacheKey, 300, user);
}
return user;
}
Cache Invalidation
// Invalidate on update
async function updateUser(id: string, data: UpdateUserInput): Promise<User> {
const user = await db.update(users)
.set(data)
.where(eq(users.id, id))
.returning();
// Invalidate cache
await redis.del(`user:${id}`);
// Also invalidate list caches
await redis.del('users:list');
return user[0];
}
Rate Limiting
import { Ratelimit } from '@upstash/ratelimit';
const ratelimit = new Ratelimit({
redis,
limiter: Ratelimit.slidingWindow(10, '10 s'), // 10 requests per 10 seconds
analytics: true,
});
// In API route or middleware
export async function POST(request: Request) {
const ip = request.headers.get('x-forwarded-for') ?? 'anonymous';
const { success, limit, reset, remaining } = await ratelimit.limit(ip);
if (!success) {
return new Response('Too Many Requests', {
status: 429,
headers: {
'X-RateLimit-Limit': limit.toString(),
'X-RateLimit-Remaining': remaining.toString(),
'X-RateLimit-Reset': reset.toString(),
},
});
}
// Process request...
}
Session Storage
interface Session {
userId: string;
expiresAt: number;
}
async function createSession(userId: string): Promise<string> {
const sessionId = crypto.randomUUID();
const session: Session = {
userId,
expiresAt: Date.now() + 7 * 24 * 60 * 60 * 1000, // 7 days
};
await redis.setex(`session:${sessionId}`, 7 * 24 * 60 * 60, session);
return sessionId;
}
async function getSession(sessionId: string): Promise<Session | null> {
return await redis.get<Session>(`session:${sessionId}`);
}
async function deleteSession(sessionId: string): Promise<void> {
await redis.del(`session:${sessionId}`);
}
Pub/Sub for Real-time
// Publisher
async function publishEvent(channel: string, data: unknown): Promise<void> {
await redis.publish(channel, JSON.stringify(data));
}
// Usage
await publishEvent('user:updates', { userId: '123', action: 'updated' });
Leaderboard
// Add score
await redis.zadd('leaderboard', { score: 100, member: 'user:123' });
// Get top 10
const topUsers = await redis.zrevrange('leaderboard', 0, 9, { withScores: true });
// Get user rank
const rank = await redis.zrevrank('leaderboard', 'user:123');
Cache Patterns
// Cache-aside pattern
async function getData<T>(
key: string,
fetcher: () => Promise<T>,
ttl: number = 300
): Promise<T> {
const cached = await redis.get<T>(key);
if (cached) return cached;
const data = await fetcher();
await redis.setex(key, ttl, data);
return data;
}
// Usage
const user = await getData(
`user:${id}`,
() => db.query.users.findFirst({ where: eq(users.id, id) }),
300
);