mirror of
https://github.com/ajayyy/SponsorBlockServer.git
synced 2025-12-10 21:47:02 +03:00
Add read only redis ability
This commit is contained in:
@@ -139,6 +139,15 @@ addDefaults(config, {
|
||||
expiryTime: 24 * 60 * 60,
|
||||
getTimeout: 40
|
||||
},
|
||||
redisRead: {
|
||||
enabled: false,
|
||||
socket: {
|
||||
host: "",
|
||||
port: 0
|
||||
},
|
||||
disableOfflineQueue: true,
|
||||
weight: 1
|
||||
},
|
||||
patreon: {
|
||||
clientId: "",
|
||||
clientSecret: "",
|
||||
|
||||
@@ -178,11 +178,11 @@ export class Postgres implements IDatabase {
|
||||
|
||||
private getPool(type: string, options: QueryOption): Pool {
|
||||
const readAvailable = this.poolRead && options.useReplica && this.isReadQuery(type);
|
||||
const ignroreReadDueToFailure = this.config.postgresReadOnly.fallbackOnFail
|
||||
const ignoreReadDueToFailure = this.config.postgresReadOnly.fallbackOnFail
|
||||
&& this.lastPoolReadFail > Date.now() - 1000 * 30;
|
||||
const readDueToFailure = this.config.postgresReadOnly.fallbackOnFail
|
||||
&& this.lastPoolFail > Date.now() - 1000 * 30;
|
||||
if (readAvailable && !ignroreReadDueToFailure && (options.forceReplica || readDueToFailure ||
|
||||
if (readAvailable && !ignoreReadDueToFailure && (options.forceReplica || readDueToFailure ||
|
||||
Math.random() > 1 / (this.config.postgresReadOnly.weight + 1))) {
|
||||
return this.poolRead;
|
||||
} else {
|
||||
|
||||
@@ -7,6 +7,11 @@ interface RedisConfig extends redis.RedisClientOptions {
|
||||
getTimeout: number;
|
||||
}
|
||||
|
||||
interface RedisReadOnlyConfig extends redis.RedisClientOptions {
|
||||
enabled: boolean;
|
||||
weight: number;
|
||||
}
|
||||
|
||||
export interface CustomPostgresConfig extends PoolConfig {
|
||||
enabled: boolean;
|
||||
maxTries: number;
|
||||
@@ -61,6 +66,7 @@ export interface SBSConfig {
|
||||
minimumPrefix?: string;
|
||||
maximumPrefix?: string;
|
||||
redis?: RedisConfig;
|
||||
redisRead?: RedisReadOnlyConfig;
|
||||
maxRewardTimePerSegmentInSeconds?: number;
|
||||
postgres?: CustomPostgresConfig;
|
||||
postgresReadOnly?: CustomPostgresReadOnlyConfig;
|
||||
|
||||
@@ -25,19 +25,35 @@ let exportClient: RedisSB = {
|
||||
quit: () => new Promise((resolve) => resolve(null)),
|
||||
};
|
||||
|
||||
let lastClientFail = 0;
|
||||
let lastReadFail = 0;
|
||||
|
||||
if (config.redis?.enabled) {
|
||||
Logger.info("Connected to redis");
|
||||
const client = createClient(config.redis);
|
||||
const readClient = config.redisRead?.enabled ? createClient(config.redisRead) : null;
|
||||
void client.connect(); // void as we don't care about the promise
|
||||
void readClient?.connect();
|
||||
exportClient = client as RedisSB;
|
||||
|
||||
|
||||
const get = client.get.bind(client);
|
||||
const getRead = readClient?.get?.bind(readClient);
|
||||
exportClient.get = (key) => new Promise((resolve, reject) => {
|
||||
const timeout = config.redis.getTimeout ? setTimeout(() => reject(), config.redis.getTimeout) : null;
|
||||
get(key).then((reply) => {
|
||||
const chosenGet = pickChoice(get, getRead);
|
||||
chosenGet(key).then((reply) => {
|
||||
if (timeout !== null) clearTimeout(timeout);
|
||||
resolve(reply);
|
||||
}).catch((err) => reject(err));
|
||||
}).catch((err) => {
|
||||
if (chosenGet === get) {
|
||||
lastClientFail = Date.now();
|
||||
} else {
|
||||
lastReadFail = Date.now();
|
||||
}
|
||||
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
exportClient.increment = (key) => new Promise((resolve, reject) =>
|
||||
void client.multi()
|
||||
@@ -48,11 +64,31 @@ if (config.redis?.enabled) {
|
||||
.catch((err) => reject(err))
|
||||
);
|
||||
client.on("error", function(error) {
|
||||
lastClientFail = Date.now();
|
||||
Logger.error(`Redis Error: ${error}`);
|
||||
});
|
||||
client.on("reconnect", () => {
|
||||
Logger.info("Redis: trying to reconnect");
|
||||
});
|
||||
readClient?.on("error", function(error) {
|
||||
lastReadFail = Date.now();
|
||||
Logger.error(`Redis Read-Only Error: ${error}`);
|
||||
});
|
||||
readClient?.on("reconnect", () => {
|
||||
Logger.info("Redis Read-Only: trying to reconnect");
|
||||
});
|
||||
}
|
||||
|
||||
function pickChoice<T>(client: T, readClient: T): T {
|
||||
const readAvailable = !!readClient;
|
||||
const ignoreReadDueToFailure = lastReadFail > Date.now() - 1000 * 30;
|
||||
const readDueToFailure = lastClientFail > Date.now() - 1000 * 30;
|
||||
if (readAvailable && !ignoreReadDueToFailure && (readDueToFailure ||
|
||||
Math.random() > 1 / (config.redisRead?.weight + 1))) {
|
||||
return readClient;
|
||||
} else {
|
||||
return client;
|
||||
}
|
||||
}
|
||||
|
||||
export default exportClient;
|
||||
|
||||
Reference in New Issue
Block a user