36 lines
1.3 KiB
TypeScript
36 lines
1.3 KiB
TypeScript
import Redis from "ioredis"
|
|
|
|
import { config } from "./config"
|
|
|
|
/**
|
|
* 每条连接都要挂 error 监听。
|
|
*
|
|
* ioredis 对没有监听者的 error 走 silentEmit —— 不会像普通 EventEmitter 那样崩进程,
|
|
* 但会把连接错误直接 `console.error("[ioredis] Unhandled error event:", ...)` 打到
|
|
* stderr,绕开这里的日志,而且不说是哪条连接出的事。这个进程同时开着会话读写、
|
|
* 两条队列、一条订阅,出问题时「哪条」正是要先知道的。
|
|
*/
|
|
function withErrorLogging(client: Redis, name: string) {
|
|
client.on("error", (error) => {
|
|
console.error(`Redis connection error (${name})`, error)
|
|
})
|
|
return client
|
|
}
|
|
|
|
/**
|
|
* 会话、限流、发布事件都走这条。`maxRetriesPerRequest: 1` 是故意的:每个带鉴权的
|
|
* 请求都要读一次会话,Redis 不可用时快速失败成 500,比让请求挂在重试里更好。
|
|
*/
|
|
export const redis = withErrorLogging(
|
|
new Redis(config.redisUrl, { maxRetriesPerRequest: 1 }),
|
|
"main",
|
|
)
|
|
|
|
export function createBlockingRedis() {
|
|
return withErrorLogging(new Redis(config.redisUrl, { maxRetriesPerRequest: null }), "blocking")
|
|
}
|
|
|
|
export function createSubscriberRedis() {
|
|
return withErrorLogging(new Redis(config.redisUrl, { maxRetriesPerRequest: null }), "subscriber")
|
|
}
|