원클릭으로
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