Reputation: 166166
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.
Upvotes: 2
Views: 3828
Reputation: 438
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
Upvotes: 5
Reputation: 81
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}`))
Upvotes: 2