I've got some legacy code that I'm upgrading from version 3 of the Node.js redis library to version 4 of the Node.js redis library. The basic shape of the code looks like this
var redis = require('redis')
var client = redis.createClient({
port: '6379',
host: process.env.REDIS_HOST,
legacyMode: true
})
client.connect()
client.flushall(function (err, reply) {
client.hkeys('hash key', function (err, replies) {
console.log("key set done")
client.quit()
})
})
console.log("main done")
When I run this code with [email protected], I get the following error, and node.js exits with a non-zero status code
main done
key set done
events.js:292
throw er; // Unhandled 'error' event
^
SocketClosedUnexpectedlyError: Socket closed unexpectedly
at Socket.<anonymous> (/Users/astorm/Documents/redis4/node_modules/@redis/client/dist/lib/client/socket.js:182:118)
at Object.onceWrapper (events.js:422:26)
at Socket.emit (events.js:315:20)
at TCP.<anonymous> (net.js:673:12)
Emitted 'error' event on Commander instance at:
at RedisSocket.<anonymous> (/Users/astorm/Documents/redis4/node_modules/@redis/client/dist/lib/client/index.js:350:14)
at RedisSocket.emit (events.js:315:20)
at RedisSocket._RedisSocket_onSocketError (/Users/astorm/Documents/redis4/node_modules/@redis/client/dist/lib/client/socket.js:205:10)
at Socket.<anonymous> (/Users/astorm/Documents/redis4/node_modules/@redis/client/dist/lib/client/socket.js:182:107)
at Object.onceWrapper (events.js:422:26)
at Socket.emit (events.js:315:20)
at TCP.<anonymous> (net.js:673:12)
While in [email protected] it runs (minus the client.connect()) without issue.
I've been able to work around this by replacing client.quit() with client.disconnect(), but the actual code is a little more complex than the above example and I'd rather use the graceful shutdown of client.quit than the harsher "SHUT IT DOWN NOW" of client.disconnect().
Does anyone know what the issue here might be? Why is redis@4 failing with a SocketClosedUnexpectedlyError: Socket closed unexpectedly error.
I have the same bug on a express js project,
const redisClient = createClient({
legacyMode: true,
url: process.env.REDIS_URL,
});
my error:
web.1 State changed from up to crashed
web.1 ERROR uncaughtException Socket closed unexpectedly
web.1 SocketClosedUnexpectedlyError: Socket closed unexpectedly
i change the code to
const redisClient = createClient({
legacyMode: true,
url: process.env.REDIS_URL,
pingInterval: 1000,
});
the error disappear, i waited for an hour. So pingInterval helped me to keep socket alive
What I found so far is that after a while (keepAlive default is 5 minutes) without any requests the Redis client closes and throws an error event, but if you don't handle this event it will crash your application. My solution for that was:
/* eslint-disable no-inline-comments */
import type { RedisClientType } from 'redis'
import { createClient } from 'redis'
import { config } from '@app/config'
import { logger } from '@app/utils/logger'
let redisClient: RedisClientType
let isReady: boolean
const cacheOptions = {
url: config.redis.tlsFlag ? config.redis.urlTls : config.redis.url,
}
if (config.redis.tlsFlag) {
Object.assign(cacheOptions, {
socket: {
// keepAlive: 300, // 5 minutes DEFAULT
tls: false,
},
})
}
async function getCache(): Promise<RedisClientType> {
if (!isReady) {
redisClient = createClient({
...cacheOptions,
})
redisClient.on('error', err => logger.error(`Redis Error: ${err}`))
redisClient.on('connect', () => logger.info('Redis connected'))
redisClient.on('reconnecting', () => logger.info('Redis reconnecting'))
redisClient.on('ready', () => {
isReady = true
logger.info('Redis ready!')
})
await redisClient.connect()
}
return redisClient
}
getCache().then(connection => {
redisClient = connection
}).catch(err => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
logger.error({ err }, 'Failed to connect to Redis')
})
export {
getCache,
}
anyway... in your situation try to handle the error event
client.on('error', err => logger.error(`Redis Error: ${err}`))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With