一键导入
redis-patterns
Redis patterns including caching strategies, pub/sub, streams for event processing, Lua scripts, and data structures
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Redis patterns including caching strategies, pub/sub, streams for event processing, Lua scripts, and data structures
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Route broad or ambiguous AgentKit SEO work to the right module while keeping context scoped. Use when a request spans multiple surfaces, asks for overall digital-presence strategy, involves provider or install architecture, needs agent-context planning, or the correct platform skill is unclear.
Persistent memory system for Claude Code. Two-layer architecture (hot cache + knowledge wiki), safety hooks, /close-day end-of-day synthesis. Zero external dependencies.
Claude-native deep research using DAG-based query planning, parallel subagent execution, and gap-driven iteration. No external API needed.
Web accessibility patterns for WCAG 2.2 compliance including ARIA, keyboard navigation, screen readers, and testing
Authentication and authorization patterns including OAuth2, JWT, RBAC, session management, and PKCE flows
AWS cloud patterns for Lambda, ECS, S3, DynamoDB, and Infrastructure as Code with CDK/Terraform
| name | redis-patterns |
| description | Redis patterns including caching strategies, pub/sub, streams for event processing, Lua scripts, and data structures |
async function getUser(userId: string): Promise<User> {
const cacheKey = `user:${userId}`;
const cached = await redis.get(cacheKey);
if (cached) {
return JSON.parse(cached);
}
const user = await db.user.findUnique({ where: { id: userId } });
if (user) {
await redis.set(cacheKey, JSON.stringify(user), "EX", 3600);
}
return user;
}
async function invalidateUser(userId: string): Promise<void> {
await redis.del(`user:${userId}`);
await redis.del(`user:${userId}:orders`);
}
async function cacheAside<T>(
key: string,
ttlSeconds: number,
fetcher: () => Promise<T>
): Promise<T> {
const cached = await redis.get(key);
if (cached) return JSON.parse(cached);
const value = await fetcher();
await redis.set(key, JSON.stringify(value), "EX", ttlSeconds);
return value;
}
async function isRateLimited(
clientId: string,
limit: number,
windowSeconds: number
): Promise<boolean> {
const key = `ratelimit:${clientId}`;
const now = Date.now();
const windowStart = now - windowSeconds * 1000;
const pipe = redis.multi();
pipe.zremrangebyscore(key, 0, windowStart);
pipe.zadd(key, now, `${now}:${crypto.randomUUID()}`);
pipe.zcard(key);
pipe.expire(key, windowSeconds);
const results = await pipe.exec();
const count = results[2][1] as number;
return count > limit;
}
const subscriber = redis.duplicate();
await subscriber.subscribe("notifications", "orders");
subscriber.on("message", (channel, message) => {
const event = JSON.parse(message);
switch (channel) {
case "notifications":
handleNotification(event);
break;
case "orders":
handleOrderEvent(event);
break;
}
});
async function publishEvent(channel: string, event: object): Promise<void> {
await redis.publish(channel, JSON.stringify(event));
}
async function produceEvent(stream: string, event: Record<string, string>) {
await redis.xadd(stream, "*", ...Object.entries(event).flat());
}
async function consumeEvents(
stream: string,
group: string,
consumer: string
) {
try {
await redis.xgroup("CREATE", stream, group, "0", "MKSTREAM");
} catch {
// group already exists
}
while (true) {
const results = await redis.xreadgroup(
"GROUP", group, consumer,
"COUNT", 10,
"BLOCK", 5000,
"STREAMS", stream, ">"
);
if (!results) continue;
for (const [, messages] of results) {
for (const [id, fields] of messages) {
await processMessage(fields);
await redis.xack(stream, group, id);
}
}
}
}
Streams provide durable, consumer-group-based event processing with acknowledgment and replay.
const acquireLock = `
local key = KEYS[1]
local token = ARGV[1]
local ttl = ARGV[2]
if redis.call("SET", key, token, "NX", "EX", ttl) then
return 1
end
return 0
`;
const releaseLock = `
local key = KEYS[1]
local token = ARGV[1]
if redis.call("GET", key) == token then
return redis.call("DEL", key)
end
return 0
`;
async function withLock<T>(
resource: string,
ttl: number,
fn: () => Promise<T>
): Promise<T> {
const token = crypto.randomUUID();
const acquired = await redis.eval(acquireLock, 1, `lock:${resource}`, token, ttl);
if (!acquired) throw new Error("Failed to acquire lock");
try {
return await fn();
} finally {
await redis.eval(releaseLock, 1, `lock:${resource}`, token);
}
}
KEYS * in production (blocks the server; use SCAN instead)entity:id:field)SCAN used instead of KEYS for pattern matching in production