在项目中碰到一个问题,以前一直好的程序,增加了些代码,突然爆redis异常:
Tried to use a connection from a child process without reconnecting. You need to reconnect to Redis after forking.
意思很明确,就是你fork了进程,子进程中的redis连接没法用了,要重连。但是为什么呢。
项目是rails的,一直没有问题,有独立跑的进程,这个进程会先加载rails环境,然后运行sneaker worker,错误就是在从sneaker worker里面爆出来的,在里面会使用配置在rails initializer里处使用的缓存工具。
缓存工具是同事写的第三方的gem包app_cache,在initializer里面初始化。
分析了前因后果,原因找到了,这个缓存工具初始化的时候就会连接redis,独立进程跑的时候就会加载并连接redis,然后这个进程fork子进程,子进程中如果继续使用这个连接就报错了。
但是我直接在sneaker worker里面重新设置缓存工具的redis连接,依然报错,这是为何,打开app_cache的源码,发现其连接创建的代码是:
redis = Redis.current.nil? ? Redis.new(:url => options\[:url\]) : Redis.current
问题就出在Redis.current上面,因为是进程fork,子进程的Redis.current并不为nil,此时就会使用这个连接,但是很显然这个连接是父进程创建的,这里是无效的,如果要去使用,就会报开始那个异常。
解决起来很简单,改下app_cache,把链接创建代码改为如下:
redis = Redis.new(:url => options\[:url\])