UNPKG

dailyhot-api

Version:
127 lines (126 loc) 3.91 kB
import { config } from "../config.js"; import { stringify, parse } from "flatted"; import logger from "./logger.js"; import NodeCache from "node-cache"; import Redis from "ioredis"; // init NodeCache const cache = new NodeCache({ // 缓存过期时间( 秒 ) stdTTL: config.CACHE_TTL, // 定期检查过期缓存( 秒 ) checkperiod: 600, // 克隆变量 useClones: false, // 最大键值对 maxKeys: 100, }); // init Redis client const redis = new Redis({ host: config.REDIS_HOST, port: config.REDIS_PORT, password: config.REDIS_PASSWORD, maxRetriesPerRequest: 5, // 重试策略:最小延迟 50ms,最大延迟 2s retryStrategy: (times) => Math.min(times * 50, 2000), // 仅在第一次建立连接 lazyConnect: true, }); // Redis 是否可用 let isRedisAvailable = false; let isRedisTried = false; // Redis 连接状态 const ensureRedisConnection = async () => { if (isRedisTried) return; try { if (redis.status !== "ready" && redis.status !== "connecting") await redis.connect(); isRedisAvailable = true; isRedisTried = true; logger.info("📦 [Redis] connected successfully."); } catch (error) { isRedisAvailable = false; isRedisTried = true; logger.error(`📦 [Redis] connection failed: ${error instanceof Error ? error.message : "Unknown error"}`); } }; // Redis 事件监听 redis.on("error", (err) => { if (!isRedisTried) { isRedisAvailable = false; isRedisTried = true; logger.error(`📦 [Redis] connection failed: ${err instanceof Error ? err.message : "Unknown error"}`); } }); // NodeCache 事件监听 cache.on("expired", (key) => { logger.info(`⏳ [NodeCache] Key "${key}" has expired.`); }); cache.on("del", (key) => { logger.info(`🗑️ [NodeCache] Key "${key}" has been deleted.`); }); /** * 从缓存中获取数据 * @param key 缓存键 * @returns 缓存数据 */ export const getCache = async (key) => { await ensureRedisConnection(); if (isRedisAvailable) { try { const redisResult = await redis.get(key); if (redisResult) return parse(redisResult); } catch (error) { logger.error(`📦 [Redis] get error: ${error instanceof Error ? error.message : "Unknown error"}`); } } return cache.get(key); }; /** * 将数据写入缓存 * @param key 缓存键 * @param value 缓存值 * @param ttl 缓存过期时间( 秒 ) * @returns 是否写入成功 */ export const setCache = async (key, value, ttl = config.CACHE_TTL) => { // 尝试写入 Redis if (isRedisAvailable && !Buffer.isBuffer(value?.data)) { try { await redis.set(key, stringify(value), "EX", ttl); if (logger) logger.info(`💾 [REDIS] ${key} has been cached`); } catch (error) { logger.error(`📦 [Redis] set error: ${error instanceof Error ? error.message : "Unknown error"}`); } } const success = cache.set(key, value, ttl); if (logger) logger.info(`💾 [NodeCache] ${key} has been cached`); return success; }; /** * 从缓存中删除数据 * @param key 缓存键 * @returns 是否删除成功 */ export const delCache = async (key) => { let redisSuccess = true; try { await redis.del(key); logger.info(`🗑️ [REDIS] ${key} has been deleted from Redis`); } catch (error) { redisSuccess = false; logger.error(`📦 [Redis] del error: ${error instanceof Error ? error.message : "Unknown error"}`); } // 尝试删除 NodeCache const nodeCacheSuccess = cache.del(key) > 0; if (logger) logger.info(`🗑️ [CACHE] ${key} has been deleted from NodeCache`); return redisSuccess && nodeCacheSuccess; };