mirror of
https://github.com/imsyy/DailyHotApi.git
synced 2026-01-12 13:14:55 +08:00
🎈 perf: 优化 Redis 策略
This commit is contained in:
@@ -43,6 +43,7 @@
|
|||||||
"dayjs": "^1.11.13",
|
"dayjs": "^1.11.13",
|
||||||
"dotenv": "^16.4.6",
|
"dotenv": "^16.4.6",
|
||||||
"feed": "^4.2.2",
|
"feed": "^4.2.2",
|
||||||
|
"flatted": "^3.3.2",
|
||||||
"hono": "^4.6.12",
|
"hono": "^4.6.12",
|
||||||
"iconv-lite": "^0.6.3",
|
"iconv-lite": "^0.6.3",
|
||||||
"ioredis": "^5.4.1",
|
"ioredis": "^5.4.1",
|
||||||
@@ -50,7 +51,6 @@
|
|||||||
"node-cache": "^5.1.2",
|
"node-cache": "^5.1.2",
|
||||||
"rss-parser": "^3.13.0",
|
"rss-parser": "^3.13.0",
|
||||||
"user-agents": "^1.1.379",
|
"user-agents": "^1.1.379",
|
||||||
"uuid": "^11.0.3",
|
|
||||||
"winston": "^3.17.0"
|
"winston": "^3.17.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
12
pnpm-lock.yaml
generated
12
pnpm-lock.yaml
generated
@@ -29,6 +29,9 @@ importers:
|
|||||||
feed:
|
feed:
|
||||||
specifier: ^4.2.2
|
specifier: ^4.2.2
|
||||||
version: 4.2.2
|
version: 4.2.2
|
||||||
|
flatted:
|
||||||
|
specifier: ^3.3.2
|
||||||
|
version: 3.3.2
|
||||||
hono:
|
hono:
|
||||||
specifier: ^4.6.12
|
specifier: ^4.6.12
|
||||||
version: 4.6.12
|
version: 4.6.12
|
||||||
@@ -50,9 +53,6 @@ importers:
|
|||||||
user-agents:
|
user-agents:
|
||||||
specifier: ^1.1.379
|
specifier: ^1.1.379
|
||||||
version: 1.1.379
|
version: 1.1.379
|
||||||
uuid:
|
|
||||||
specifier: ^11.0.3
|
|
||||||
version: 11.0.3
|
|
||||||
winston:
|
winston:
|
||||||
specifier: ^3.17.0
|
specifier: ^3.17.0
|
||||||
version: 3.17.0
|
version: 3.17.0
|
||||||
@@ -1055,10 +1055,6 @@ packages:
|
|||||||
util-deprecate@1.0.2:
|
util-deprecate@1.0.2:
|
||||||
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
|
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
|
||||||
|
|
||||||
uuid@11.0.3:
|
|
||||||
resolution: {integrity: sha512-d0z310fCWv5dJwnX1Y/MncBAqGMKEzlBb1AOf7z9K8ALnd0utBX/msg/fA0+sbyN1ihbMsLhrBlnl1ak7Wa0rg==}
|
|
||||||
hasBin: true
|
|
||||||
|
|
||||||
whatwg-encoding@3.1.1:
|
whatwg-encoding@3.1.1:
|
||||||
resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==}
|
resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
@@ -2008,8 +2004,6 @@ snapshots:
|
|||||||
|
|
||||||
util-deprecate@1.0.2: {}
|
util-deprecate@1.0.2: {}
|
||||||
|
|
||||||
uuid@11.0.3: {}
|
|
||||||
|
|
||||||
whatwg-encoding@3.1.1:
|
whatwg-encoding@3.1.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
iconv-lite: 0.6.3
|
iconv-lite: 0.6.3
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { config } from "../config.js";
|
import { config } from "../config.js";
|
||||||
|
import { stringify, parse } from "flatted";
|
||||||
import logger from "./logger.js";
|
import logger from "./logger.js";
|
||||||
import NodeCache from "node-cache";
|
import NodeCache from "node-cache";
|
||||||
import Redis from "ioredis";
|
import Redis from "ioredis";
|
||||||
@@ -25,6 +26,9 @@ const redis = new Redis({
|
|||||||
host: config.REDIS_HOST,
|
host: config.REDIS_HOST,
|
||||||
port: config.REDIS_PORT,
|
port: config.REDIS_PORT,
|
||||||
password: config.REDIS_PASSWORD,
|
password: config.REDIS_PASSWORD,
|
||||||
|
maxRetriesPerRequest: 5,
|
||||||
|
// 重试策略:最小延迟 50ms,最大延迟 2s
|
||||||
|
retryStrategy: (times) => Math.min(times * 50, 2000),
|
||||||
// 仅在第一次建立连接
|
// 仅在第一次建立连接
|
||||||
lazyConnect: true,
|
lazyConnect: true,
|
||||||
});
|
});
|
||||||
@@ -33,7 +37,24 @@ const redis = new Redis({
|
|||||||
let isRedisAvailable: boolean = false;
|
let isRedisAvailable: boolean = false;
|
||||||
let isRedisTried: boolean = false;
|
let isRedisTried: boolean = false;
|
||||||
|
|
||||||
// Redis 连接错误
|
// 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) => {
|
redis.on("error", (err) => {
|
||||||
if (!isRedisTried) {
|
if (!isRedisTried) {
|
||||||
isRedisAvailable = false;
|
isRedisAvailable = false;
|
||||||
@@ -44,23 +65,14 @@ redis.on("error", (err) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Redis 连接状态
|
// NodeCache 事件监听
|
||||||
const ensureRedisConnection = async () => {
|
cache.on("expired", (key) => {
|
||||||
if (!isRedisTried) {
|
logger.info(`⏳ [NodeCache] Key "${key}" has expired.`);
|
||||||
try {
|
});
|
||||||
await redis.connect();
|
|
||||||
isRedisAvailable = true;
|
cache.on("del", (key) => {
|
||||||
isRedisTried = true;
|
logger.info(`🗑️ [NodeCache] Key "${key}" has been deleted.`);
|
||||||
logger.info("📦 [Redis] connected successfully.");
|
});
|
||||||
} catch (error) {
|
|
||||||
isRedisAvailable = false;
|
|
||||||
isRedisTried = true;
|
|
||||||
logger.error(
|
|
||||||
`📦 [Redis] connection failed: ${error instanceof Error ? error.message : "Unknown error"}`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 从缓存中获取数据
|
* 从缓存中获取数据
|
||||||
@@ -72,10 +84,7 @@ export const getCache = async (key: string): Promise<CacheData | undefined> => {
|
|||||||
if (isRedisAvailable) {
|
if (isRedisAvailable) {
|
||||||
try {
|
try {
|
||||||
const redisResult = await redis.get(key);
|
const redisResult = await redis.get(key);
|
||||||
if (redisResult) {
|
if (redisResult) return parse(redisResult);
|
||||||
const data = JSON.parse(redisResult);
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error(
|
logger.error(
|
||||||
`📦 [Redis] get error: ${error instanceof Error ? error.message : "Unknown error"}`,
|
`📦 [Redis] get error: ${error instanceof Error ? error.message : "Unknown error"}`,
|
||||||
@@ -100,7 +109,7 @@ export const setCache = async (
|
|||||||
// 尝试写入 Redis
|
// 尝试写入 Redis
|
||||||
if (isRedisAvailable && !Buffer.isBuffer(value?.data)) {
|
if (isRedisAvailable && !Buffer.isBuffer(value?.data)) {
|
||||||
try {
|
try {
|
||||||
await redis.set(key, JSON.stringify(value), "EX", ttl);
|
await redis.set(key, stringify(value), "EX", ttl);
|
||||||
if (logger) logger.info(`💾 [REDIS] ${key} has been cached`);
|
if (logger) logger.info(`💾 [REDIS] ${key} has been cached`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error(
|
logger.error(
|
||||||
@@ -120,16 +129,14 @@ export const setCache = async (
|
|||||||
*/
|
*/
|
||||||
export const delCache = async (key: string): Promise<boolean> => {
|
export const delCache = async (key: string): Promise<boolean> => {
|
||||||
let redisSuccess = true;
|
let redisSuccess = true;
|
||||||
if (isRedisAvailable) {
|
try {
|
||||||
try {
|
await redis.del(key);
|
||||||
await redis.del(key);
|
logger.info(`🗑️ [REDIS] ${key} has been deleted from Redis`);
|
||||||
if (logger) logger.info(`🗑️ [REDIS] ${key} has been deleted from Redis`);
|
} catch (error) {
|
||||||
} catch (error) {
|
redisSuccess = false;
|
||||||
logger.error(
|
logger.error(
|
||||||
`📦 [Redis] del error: ${error instanceof Error ? error.message : "Unknown error"}`,
|
`📦 [Redis] del error: ${error instanceof Error ? error.message : "Unknown error"}`,
|
||||||
);
|
);
|
||||||
redisSuccess = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// 尝试删除 NodeCache
|
// 尝试删除 NodeCache
|
||||||
const nodeCacheSuccess = cache.del(key) > 0;
|
const nodeCacheSuccess = cache.del(key) > 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user