Fix: Add keep-alive options to Redis clients to prevent idle timeouts and socket closing. (#4377)
* redis keepalive mechanism for all redis * removed offline queue commands * Simplified changes for consistency. Added REDIS_KEEP_ALIVE env variable. * update redis socket alive env variable * lint fix --------- Co-authored-by: Henry <hzj94@hotmail.com> Co-authored-by: Henry Heng <henryheng@flowiseai.com>
This commit is contained in:
parent
98e75ad7d6
commit
eadf1b11b3
|
|
@ -101,4 +101,5 @@ BLOB_STORAGE_PATH=/root/.flowise/storage
|
||||||
# REDIS_CERT=
|
# REDIS_CERT=
|
||||||
# REDIS_KEY=
|
# REDIS_KEY=
|
||||||
# REDIS_CA=
|
# REDIS_CA=
|
||||||
# ENABLE_BULLMQ_DASHBOARD=
|
# REDIS_KEEP_ALIVE=
|
||||||
|
# ENABLE_BULLMQ_DASHBOARD=
|
||||||
|
|
@ -49,6 +49,7 @@ services:
|
||||||
- REDIS_CERT=${REDIS_CERT}
|
- REDIS_CERT=${REDIS_CERT}
|
||||||
- REDIS_KEY=${REDIS_KEY}
|
- REDIS_KEY=${REDIS_KEY}
|
||||||
- REDIS_CA=${REDIS_CA}
|
- REDIS_CA=${REDIS_CA}
|
||||||
|
- REDIS_KEEP_ALIVE=${REDIS_KEEP_ALIVE}
|
||||||
- ENABLE_BULLMQ_DASHBOARD=${ENABLE_BULLMQ_DASHBOARD}
|
- ENABLE_BULLMQ_DASHBOARD=${ENABLE_BULLMQ_DASHBOARD}
|
||||||
ports:
|
ports:
|
||||||
- '${PORT}:${PORT}'
|
- '${PORT}:${PORT}'
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,7 @@ services:
|
||||||
- REDIS_CERT=${REDIS_CERT}
|
- REDIS_CERT=${REDIS_CERT}
|
||||||
- REDIS_KEY=${REDIS_KEY}
|
- REDIS_KEY=${REDIS_KEY}
|
||||||
- REDIS_CA=${REDIS_CA}
|
- REDIS_CA=${REDIS_CA}
|
||||||
|
- REDIS_KEEP_ALIVE=${REDIS_KEEP_ALIVE}
|
||||||
- ENABLE_BULLMQ_DASHBOARD=${ENABLE_BULLMQ_DASHBOARD}
|
- ENABLE_BULLMQ_DASHBOARD=${ENABLE_BULLMQ_DASHBOARD}
|
||||||
ports:
|
ports:
|
||||||
- '${PORT}:${PORT}'
|
- '${PORT}:${PORT}'
|
||||||
|
|
|
||||||
|
|
@ -126,10 +126,19 @@ const getRedisClient = async (nodeData: INodeData, options: ICommonObject) => {
|
||||||
host,
|
host,
|
||||||
username,
|
username,
|
||||||
password,
|
password,
|
||||||
|
keepAlive:
|
||||||
|
process.env.REDIS_KEEP_ALIVE && !isNaN(parseInt(process.env.REDIS_KEEP_ALIVE, 10))
|
||||||
|
? parseInt(process.env.REDIS_KEEP_ALIVE, 10)
|
||||||
|
: undefined,
|
||||||
...tlsOptions
|
...tlsOptions
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
client = new Redis(redisUrl)
|
client = new Redis(redisUrl, {
|
||||||
|
keepAlive:
|
||||||
|
process.env.REDIS_KEEP_ALIVE && !isNaN(parseInt(process.env.REDIS_KEEP_ALIVE, 10))
|
||||||
|
? parseInt(process.env.REDIS_KEEP_ALIVE, 10)
|
||||||
|
: undefined
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return client
|
return client
|
||||||
|
|
|
||||||
|
|
@ -83,10 +83,19 @@ class RedisEmbeddingsCache implements INode {
|
||||||
host,
|
host,
|
||||||
username,
|
username,
|
||||||
password,
|
password,
|
||||||
|
keepAlive:
|
||||||
|
process.env.REDIS_KEEP_ALIVE && !isNaN(parseInt(process.env.REDIS_KEEP_ALIVE, 10))
|
||||||
|
? parseInt(process.env.REDIS_KEEP_ALIVE, 10)
|
||||||
|
: undefined,
|
||||||
...tlsOptions
|
...tlsOptions
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
client = new Redis(redisUrl)
|
client = new Redis(redisUrl, {
|
||||||
|
keepAlive:
|
||||||
|
process.env.REDIS_KEEP_ALIVE && !isNaN(parseInt(process.env.REDIS_KEEP_ALIVE, 10))
|
||||||
|
? parseInt(process.env.REDIS_KEEP_ALIVE, 10)
|
||||||
|
: undefined
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
ttl ??= '3600'
|
ttl ??= '3600'
|
||||||
|
|
|
||||||
|
|
@ -132,7 +132,21 @@ class BufferMemoryExtended extends FlowiseMemory implements MemoryMethods {
|
||||||
}
|
}
|
||||||
|
|
||||||
private async withRedisClient<T>(fn: (client: Redis) => Promise<T>): Promise<T> {
|
private async withRedisClient<T>(fn: (client: Redis) => Promise<T>): Promise<T> {
|
||||||
const client = typeof this.redisOptions === 'string' ? new Redis(this.redisOptions) : new Redis(this.redisOptions)
|
const client =
|
||||||
|
typeof this.redisOptions === 'string'
|
||||||
|
? new Redis(this.redisOptions, {
|
||||||
|
keepAlive:
|
||||||
|
process.env.REDIS_KEEP_ALIVE && !isNaN(parseInt(process.env.REDIS_KEEP_ALIVE, 10))
|
||||||
|
? parseInt(process.env.REDIS_KEEP_ALIVE, 10)
|
||||||
|
: undefined
|
||||||
|
})
|
||||||
|
: new Redis({
|
||||||
|
...this.redisOptions,
|
||||||
|
keepAlive:
|
||||||
|
process.env.REDIS_KEEP_ALIVE && !isNaN(parseInt(process.env.REDIS_KEEP_ALIVE, 10))
|
||||||
|
? parseInt(process.env.REDIS_KEEP_ALIVE, 10)
|
||||||
|
: undefined
|
||||||
|
})
|
||||||
try {
|
try {
|
||||||
return await fn(client)
|
return await fn(client)
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
||||||
|
|
@ -147,7 +147,15 @@ class Redis_VectorStores implements INode {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const redisClient = createClient({ url: redisUrl })
|
const redisClient = createClient({
|
||||||
|
url: redisUrl,
|
||||||
|
socket: {
|
||||||
|
keepAlive:
|
||||||
|
process.env.REDIS_KEEP_ALIVE && !isNaN(parseInt(process.env.REDIS_KEEP_ALIVE, 10))
|
||||||
|
? parseInt(process.env.REDIS_KEEP_ALIVE, 10)
|
||||||
|
: undefined // milliseconds
|
||||||
|
}
|
||||||
|
})
|
||||||
await redisClient.connect()
|
await redisClient.connect()
|
||||||
|
|
||||||
const storeConfig: RedisVectorStoreConfig = {
|
const storeConfig: RedisVectorStoreConfig = {
|
||||||
|
|
@ -212,7 +220,15 @@ class Redis_VectorStores implements INode {
|
||||||
redisUrl = 'redis://' + username + ':' + password + '@' + host + ':' + portStr
|
redisUrl = 'redis://' + username + ':' + password + '@' + host + ':' + portStr
|
||||||
}
|
}
|
||||||
|
|
||||||
const redisClient = createClient({ url: redisUrl })
|
const redisClient = createClient({
|
||||||
|
url: redisUrl,
|
||||||
|
socket: {
|
||||||
|
keepAlive:
|
||||||
|
process.env.REDIS_KEEP_ALIVE && !isNaN(parseInt(process.env.REDIS_KEEP_ALIVE, 10))
|
||||||
|
? parseInt(process.env.REDIS_KEEP_ALIVE, 10)
|
||||||
|
: undefined // milliseconds
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const storeConfig: RedisVectorStoreConfig = {
|
const storeConfig: RedisVectorStoreConfig = {
|
||||||
redisClient: redisClient,
|
redisClient: redisClient,
|
||||||
|
|
|
||||||
|
|
@ -99,4 +99,5 @@ PORT=3000
|
||||||
# REDIS_CERT=
|
# REDIS_CERT=
|
||||||
# REDIS_KEY=
|
# REDIS_KEY=
|
||||||
# REDIS_CA=
|
# REDIS_CA=
|
||||||
# ENABLE_BULLMQ_DASHBOARD=
|
# REDIS_KEEP_ALIVE=
|
||||||
|
# ENABLE_BULLMQ_DASHBOARD=
|
||||||
|
|
@ -12,7 +12,12 @@ export class CachePool {
|
||||||
constructor() {
|
constructor() {
|
||||||
if (process.env.MODE === MODE.QUEUE) {
|
if (process.env.MODE === MODE.QUEUE) {
|
||||||
if (process.env.REDIS_URL) {
|
if (process.env.REDIS_URL) {
|
||||||
this.redisClient = new Redis(process.env.REDIS_URL)
|
this.redisClient = new Redis(process.env.REDIS_URL, {
|
||||||
|
keepAlive:
|
||||||
|
process.env.REDIS_KEEP_ALIVE && !isNaN(parseInt(process.env.REDIS_KEEP_ALIVE, 10))
|
||||||
|
? parseInt(process.env.REDIS_KEEP_ALIVE, 10)
|
||||||
|
: undefined
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
this.redisClient = new Redis({
|
this.redisClient = new Redis({
|
||||||
host: process.env.REDIS_HOST || 'localhost',
|
host: process.env.REDIS_HOST || 'localhost',
|
||||||
|
|
@ -26,6 +31,10 @@ export class CachePool {
|
||||||
key: process.env.REDIS_KEY ? Buffer.from(process.env.REDIS_KEY, 'base64') : undefined,
|
key: process.env.REDIS_KEY ? Buffer.from(process.env.REDIS_KEY, 'base64') : undefined,
|
||||||
ca: process.env.REDIS_CA ? Buffer.from(process.env.REDIS_CA, 'base64') : undefined
|
ca: process.env.REDIS_CA ? Buffer.from(process.env.REDIS_CA, 'base64') : undefined
|
||||||
}
|
}
|
||||||
|
: undefined,
|
||||||
|
keepAlive:
|
||||||
|
process.env.REDIS_KEEP_ALIVE && !isNaN(parseInt(process.env.REDIS_KEEP_ALIVE, 10))
|
||||||
|
? parseInt(process.env.REDIS_KEEP_ALIVE, 10)
|
||||||
: undefined
|
: undefined
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -76,6 +76,7 @@ export abstract class BaseCommand extends Command {
|
||||||
REDIS_CERT: Flags.string(),
|
REDIS_CERT: Flags.string(),
|
||||||
REDIS_KEY: Flags.string(),
|
REDIS_KEY: Flags.string(),
|
||||||
REDIS_CA: Flags.string(),
|
REDIS_CA: Flags.string(),
|
||||||
|
REDIS_KEEP_ALIVE: Flags.string(),
|
||||||
ENABLE_BULLMQ_DASHBOARD: Flags.string()
|
ENABLE_BULLMQ_DASHBOARD: Flags.string()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -211,6 +212,7 @@ export abstract class BaseCommand extends Command {
|
||||||
if (flags.QUEUE_REDIS_EVENT_STREAM_MAX_LEN) process.env.QUEUE_REDIS_EVENT_STREAM_MAX_LEN = flags.QUEUE_REDIS_EVENT_STREAM_MAX_LEN
|
if (flags.QUEUE_REDIS_EVENT_STREAM_MAX_LEN) process.env.QUEUE_REDIS_EVENT_STREAM_MAX_LEN = flags.QUEUE_REDIS_EVENT_STREAM_MAX_LEN
|
||||||
if (flags.REMOVE_ON_AGE) process.env.REMOVE_ON_AGE = flags.REMOVE_ON_AGE
|
if (flags.REMOVE_ON_AGE) process.env.REMOVE_ON_AGE = flags.REMOVE_ON_AGE
|
||||||
if (flags.REMOVE_ON_COUNT) process.env.REMOVE_ON_COUNT = flags.REMOVE_ON_COUNT
|
if (flags.REMOVE_ON_COUNT) process.env.REMOVE_ON_COUNT = flags.REMOVE_ON_COUNT
|
||||||
|
if (flags.REDIS_KEEP_ALIVE) process.env.REDIS_KEEP_ALIVE = flags.REDIS_KEEP_ALIVE
|
||||||
if (flags.ENABLE_BULLMQ_DASHBOARD) process.env.ENABLE_BULLMQ_DASHBOARD = flags.ENABLE_BULLMQ_DASHBOARD
|
if (flags.ENABLE_BULLMQ_DASHBOARD) process.env.ENABLE_BULLMQ_DASHBOARD = flags.ENABLE_BULLMQ_DASHBOARD
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,12 @@ export class QueueManager {
|
||||||
port: parseInt(process.env.REDIS_PORT || '6379'),
|
port: parseInt(process.env.REDIS_PORT || '6379'),
|
||||||
username: process.env.REDIS_USERNAME || undefined,
|
username: process.env.REDIS_USERNAME || undefined,
|
||||||
password: process.env.REDIS_PASSWORD || undefined,
|
password: process.env.REDIS_PASSWORD || undefined,
|
||||||
tls: tlsOpts
|
tls: tlsOpts,
|
||||||
|
enableReadyCheck: true,
|
||||||
|
keepAlive:
|
||||||
|
process.env.REDIS_KEEP_ALIVE && !isNaN(parseInt(process.env.REDIS_KEEP_ALIVE, 10))
|
||||||
|
? parseInt(process.env.REDIS_KEEP_ALIVE, 10)
|
||||||
|
: undefined
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,13 @@ export class RedisEventPublisher implements IServerSideEventStreamer {
|
||||||
constructor() {
|
constructor() {
|
||||||
if (process.env.REDIS_URL) {
|
if (process.env.REDIS_URL) {
|
||||||
this.redisPublisher = createClient({
|
this.redisPublisher = createClient({
|
||||||
url: process.env.REDIS_URL
|
url: process.env.REDIS_URL,
|
||||||
|
socket: {
|
||||||
|
keepAlive:
|
||||||
|
process.env.REDIS_KEEP_ALIVE && !isNaN(parseInt(process.env.REDIS_KEEP_ALIVE, 10))
|
||||||
|
? parseInt(process.env.REDIS_KEEP_ALIVE, 10)
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
this.redisPublisher = createClient({
|
this.redisPublisher = createClient({
|
||||||
|
|
@ -19,7 +25,11 @@ export class RedisEventPublisher implements IServerSideEventStreamer {
|
||||||
tls: process.env.REDIS_TLS === 'true',
|
tls: process.env.REDIS_TLS === 'true',
|
||||||
cert: process.env.REDIS_CERT ? Buffer.from(process.env.REDIS_CERT, 'base64') : undefined,
|
cert: process.env.REDIS_CERT ? Buffer.from(process.env.REDIS_CERT, 'base64') : undefined,
|
||||||
key: process.env.REDIS_KEY ? Buffer.from(process.env.REDIS_KEY, 'base64') : undefined,
|
key: process.env.REDIS_KEY ? Buffer.from(process.env.REDIS_KEY, 'base64') : undefined,
|
||||||
ca: process.env.REDIS_CA ? Buffer.from(process.env.REDIS_CA, 'base64') : undefined
|
ca: process.env.REDIS_CA ? Buffer.from(process.env.REDIS_CA, 'base64') : undefined,
|
||||||
|
keepAlive:
|
||||||
|
process.env.REDIS_KEEP_ALIVE && !isNaN(parseInt(process.env.REDIS_KEEP_ALIVE, 10))
|
||||||
|
? parseInt(process.env.REDIS_KEEP_ALIVE, 10)
|
||||||
|
: undefined
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,13 @@ export class RedisEventSubscriber {
|
||||||
constructor(sseStreamer: SSEStreamer) {
|
constructor(sseStreamer: SSEStreamer) {
|
||||||
if (process.env.REDIS_URL) {
|
if (process.env.REDIS_URL) {
|
||||||
this.redisSubscriber = createClient({
|
this.redisSubscriber = createClient({
|
||||||
url: process.env.REDIS_URL
|
url: process.env.REDIS_URL,
|
||||||
|
socket: {
|
||||||
|
keepAlive:
|
||||||
|
process.env.REDIS_KEEP_ALIVE && !isNaN(parseInt(process.env.REDIS_KEEP_ALIVE, 10))
|
||||||
|
? parseInt(process.env.REDIS_KEEP_ALIVE, 10)
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
this.redisSubscriber = createClient({
|
this.redisSubscriber = createClient({
|
||||||
|
|
@ -21,7 +27,11 @@ export class RedisEventSubscriber {
|
||||||
tls: process.env.REDIS_TLS === 'true',
|
tls: process.env.REDIS_TLS === 'true',
|
||||||
cert: process.env.REDIS_CERT ? Buffer.from(process.env.REDIS_CERT, 'base64') : undefined,
|
cert: process.env.REDIS_CERT ? Buffer.from(process.env.REDIS_CERT, 'base64') : undefined,
|
||||||
key: process.env.REDIS_KEY ? Buffer.from(process.env.REDIS_KEY, 'base64') : undefined,
|
key: process.env.REDIS_KEY ? Buffer.from(process.env.REDIS_KEY, 'base64') : undefined,
|
||||||
ca: process.env.REDIS_CA ? Buffer.from(process.env.REDIS_CA, 'base64') : undefined
|
ca: process.env.REDIS_CA ? Buffer.from(process.env.REDIS_CA, 'base64') : undefined,
|
||||||
|
keepAlive:
|
||||||
|
process.env.REDIS_KEEP_ALIVE && !isNaN(parseInt(process.env.REDIS_KEEP_ALIVE, 10))
|
||||||
|
? parseInt(process.env.REDIS_KEEP_ALIVE, 10)
|
||||||
|
: undefined
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,12 @@ export class RateLimiterManager {
|
||||||
constructor() {
|
constructor() {
|
||||||
if (process.env.MODE === MODE.QUEUE) {
|
if (process.env.MODE === MODE.QUEUE) {
|
||||||
if (process.env.REDIS_URL) {
|
if (process.env.REDIS_URL) {
|
||||||
this.redisClient = new Redis(process.env.REDIS_URL)
|
this.redisClient = new Redis(process.env.REDIS_URL, {
|
||||||
|
keepAlive:
|
||||||
|
process.env.REDIS_KEEP_ALIVE && !isNaN(parseInt(process.env.REDIS_KEEP_ALIVE, 10))
|
||||||
|
? parseInt(process.env.REDIS_KEEP_ALIVE, 10)
|
||||||
|
: undefined
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
this.redisClient = new Redis({
|
this.redisClient = new Redis({
|
||||||
host: process.env.REDIS_HOST || 'localhost',
|
host: process.env.REDIS_HOST || 'localhost',
|
||||||
|
|
@ -38,6 +43,10 @@ export class RateLimiterManager {
|
||||||
key: process.env.REDIS_KEY ? Buffer.from(process.env.REDIS_KEY, 'base64') : undefined,
|
key: process.env.REDIS_KEY ? Buffer.from(process.env.REDIS_KEY, 'base64') : undefined,
|
||||||
ca: process.env.REDIS_CA ? Buffer.from(process.env.REDIS_CA, 'base64') : undefined
|
ca: process.env.REDIS_CA ? Buffer.from(process.env.REDIS_CA, 'base64') : undefined
|
||||||
}
|
}
|
||||||
|
: undefined,
|
||||||
|
keepAlive:
|
||||||
|
process.env.REDIS_KEEP_ALIVE && !isNaN(parseInt(process.env.REDIS_KEEP_ALIVE, 10))
|
||||||
|
? parseInt(process.env.REDIS_KEEP_ALIVE, 10)
|
||||||
: undefined
|
: undefined
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -65,7 +74,13 @@ export class RateLimiterManager {
|
||||||
port: parseInt(process.env.REDIS_PORT || '6379'),
|
port: parseInt(process.env.REDIS_PORT || '6379'),
|
||||||
username: process.env.REDIS_USERNAME || undefined,
|
username: process.env.REDIS_USERNAME || undefined,
|
||||||
password: process.env.REDIS_PASSWORD || undefined,
|
password: process.env.REDIS_PASSWORD || undefined,
|
||||||
tls: tlsOpts
|
tls: tlsOpts,
|
||||||
|
maxRetriesPerRequest: null,
|
||||||
|
enableReadyCheck: true,
|
||||||
|
keepAlive:
|
||||||
|
process.env.REDIS_KEEP_ALIVE && !isNaN(parseInt(process.env.REDIS_KEEP_ALIVE, 10))
|
||||||
|
? parseInt(process.env.REDIS_KEEP_ALIVE, 10)
|
||||||
|
: undefined
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue