Erlang Cowboy EventSource每隔60秒断开重连问题求助
先给你吃个定心丸:这绝对不是SSE标准内置的定期断开机制——SSE只会遵循你设置的retry字段调整重连间隔,不会默认搞60秒强制断开这套操作。结合你碰到的ERR_INCOMPLETE_CHUNKED_ENCODING错误,大概率是某个中间环节的超时配置在搞鬼,我给你梳理几个排查方向:
1. 检查反向代理的超时设置(如果用了Nginx/Apache)
很多人跑Cowboy时会套一层反向代理,而Nginx默认的proxy_read_timeout刚好是60秒——完美匹配你的断开间隔!如果是这种情况,修改Nginx配置:
location /eventsource { proxy_pass http://127.0.0.1:8080; proxy_http_version 1.1; proxy_set_header Connection ""; proxy_read_timeout 3600s; # 把超时时间调大,比如1小时 }
proxy_http_version 1.1和proxy_set_header Connection ""是为了保持HTTP/1.1的长连接特性,避免代理主动断开SSE连接。
2. 调整Cowboy自身的连接超时配置
如果没用到反向代理,就得看看Cowboy的服务器配置。默认情况下Cowboy可能有较短的空闲超时设置,你需要在监听器或者路由配置里把超时时间拉满:
在启动Cowboy的代码里,调整timeout参数(单位是毫秒):
{ok, _} = cowboy:start_clear( my_http_listener, [{port, 8080}], #{env => #{dispatch => Dispatch}, timeout => 3600000} % 设置为1小时的超时 )
这样能避免Cowboy服务器主动断开长时间空闲的SSE连接。
3. 添加SSE心跳包防止中间设备断开
即使服务器和代理都没设超时,路由器、防火墙这类中间设备也可能因为长时间没数据传输而主动断开连接。这时候你需要给SSE加心跳包——每隔一段时间发送一个空事件,保持连接活跃:
在Cowboy的EventSource处理函数里,加个定时任务,比如每30秒发一次空事件:
send_heartbeat(Req, State) -> timer:sleep(30000), {ok, Req2} = cowboy_req:send_events([""], Req, State), send_heartbeat(Req2, State).
启动这个心跳函数,就能让连接一直保持活跃,避免中间设备误判为空闲连接断开。
4. 排查系统TCP层的超时设置
最后可以检查Debian系统的TCP keepalive配置,看看是不是系统层面的超时在搞鬼:
用命令查看当前设置:
sysctl net.ipv4.tcp_keepalive_time
如果这个值小于60秒(一般默认是7200秒,也就是2小时),那可能需要调整:
sysctl -w net.ipv4.tcp_keepalive_time=3600
或者写入/etc/sysctl.conf让设置永久生效。
按照这个顺序排查下来,应该能解决你碰到的60秒断开问题。
内容的提问来源于stack exchange,提问作者mpc

