| import { getRedis } from "@/lib/redis"; |
| import { Logger } from "@/lib/logger"; |
|
|
| |
| |
| |
| |
| |
| |
| |
| export async function getCached<T>( |
| key: string, |
| fetcher: () => Promise<T>, |
| ttl = 300 |
| ): Promise<T> { |
| const redis = getRedis(); |
|
|
| if (!redis) { |
| return fetcher(); |
| } |
|
|
| try { |
| const cached = await redis.get(key); |
| if (cached) { |
| Logger.debug("Cache hit", { key, ttl }); |
| return JSON.parse(cached); |
| } |
|
|
| Logger.debug("Cache miss", { key }); |
| const data = await fetcher(); |
| await redis.setex(key, ttl, JSON.stringify(data)); |
| return data; |
| } catch (error) { |
| Logger.warn("Cache error, falling back to fetcher", { |
| key, |
| error: error instanceof Error ? error.message : String(error), |
| }); |
| return fetcher(); |
| } |
| } |
|
|
| |
| |
| |
| |
| export async function invalidateCache(pattern: string) { |
| const redis = getRedis(); |
|
|
| if (!redis) return; |
|
|
| try { |
| const keys = await redis.keys(pattern); |
| if (keys.length > 0) { |
| await redis.del(...keys); |
| Logger.debug("Cache invalidated", { pattern, count: keys.length }); |
| } |
| } catch (error) { |
| Logger.warn("Cache invalidation error", { |
| pattern, |
| error: error instanceof Error ? error.message : String(error), |
| }); |
| } |
| } |
|
|
| |
| |
| |
| |
| |
| |
| export async function setCache<T>( |
| key: string, |
| data: T, |
| ttl = 300 |
| ): Promise<void> { |
| const redis = getRedis(); |
|
|
| if (!redis) return; |
|
|
| try { |
| await redis.setex(key, ttl, JSON.stringify(data)); |
| Logger.debug("Cache set", { key, ttl }); |
| } catch (error) { |
| Logger.warn("Cache set error", { |
| key, |
| error: error instanceof Error ? error.message : String(error), |
| }); |
| } |
| } |
|
|
| |
| |
| |
| |
| |
| export async function getCache<T>(key: string): Promise<T | null> { |
| const redis = getRedis(); |
|
|
| if (!redis) return null; |
|
|
| try { |
| const cached = await redis.get(key); |
| return cached ? JSON.parse(cached) : null; |
| } catch (error) { |
| Logger.warn("Cache get error", { |
| key, |
| error: error instanceof Error ? error.message : String(error), |
| }); |
| return null; |
| } |
| } |
|
|
| |
| |
| |
| |
| export async function deleteCache(key: string): Promise<void> { |
| const redis = getRedis(); |
|
|
| if (!redis) return; |
|
|
| try { |
| await redis.del(key); |
| Logger.debug("Cache deleted", { key }); |
| } catch (error) { |
| Logger.warn("Cache delete error", { |
| key, |
| error: error instanceof Error ? error.message : String(error), |
| }); |
| } |
| } |
|
|
| |
| |
| |
| export const CacheKeys = { |
| |
| businesses: (userId: string) => `businesses:${userId}`, |
| businessesByCategory: (userId: string, category: string) => |
| `businesses:${userId}:${category}`, |
| businessDetail: (businessId: string) => `business:${businessId}`, |
|
|
| |
| workflows: (userId: string) => `workflows:${userId}`, |
| workflowDetail: (workflowId: string) => `workflow:${workflowId}`, |
| workflowExecutions: (workflowId: string) => `executions:${workflowId}`, |
|
|
| |
| templates: (userId: string) => `templates:${userId}`, |
| templateDetail: (templateId: string) => `template:${templateId}`, |
|
|
| |
| analytics: (userId: string, period = "day") => |
| `analytics:${userId}:${period}`, |
| userStats: (userId: string) => `stats:${userId}`, |
|
|
| |
| userProfile: (userId: string) => `user:${userId}`, |
| userSettings: (userId: string) => `settings:${userId}`, |
|
|
| |
| search: (userId: string, query: string) => |
| `search:${userId}:${query.toLowerCase()}`, |
| }; |
|
|
| |
| |
| |
| export const InvalidatePatterns = { |
| |
| businessesUpdated: (userId: string) => `businesses:${userId}:*`, |
| |
| workflowsUpdated: (userId: string) => `workflows:${userId}*`, |
| |
| templatesUpdated: (userId: string) => `templates:${userId}*`, |
| |
| userSettingsUpdated: (userId: string) => `settings:${userId}`, |
| |
| analyticsUpdated: (userId: string) => `analytics:${userId}:*`, |
| |
| allUserCache: (userId: string) => `*:${userId}*`, |
| }; |
|
|
| |
| |
| |
| |
| |
| |
| |
| export async function getCachedWithInvalidation<T>( |
| key: string, |
| fetcher: () => Promise<T>, |
| invalidateAfter: string[] = [], |
| ttl = 300 |
| ): Promise<T> { |
| const data = await getCached(key, fetcher, ttl); |
|
|
| |
| for (const pattern of invalidateAfter) { |
| await invalidateCache(pattern); |
| } |
|
|
| return data; |
| } |
|
|