docspell icon indicating copy to clipboard operation
docspell copied to clipboard

Websocket Error 1006: http4s Backend Timout After 60 Secs

Open nekrondev opened this issue 1 year ago • 4 comments

Runtime

Version: Docspell 0.41.0 (via docspell/restserver:latest) Browser: Firefox 108 / Chrome 120 Reverse proxy: Lighttpd 1.4.52 with mod_proxy and long-running websocket timeouts using the following config

$HTTP["host"] == "subdomain.mydomain.com" {
  $HTTP["url"] == "/api/v1/sec/ws" {
        proxy.server  = ("" => (("host" => "docspell-restserver", "port" => 7880)))
        proxy.header = ( "upgrade" => "enable", "connect" => "enable")
        server.max-read-idle = 86400
        server.max-write-idle = 86400
        server.max-keep-alive-idle = 86400
      }
      else {
          $HTTP["url"] =~ "^/([^.](.*))$|^/$" {
          proxy.server  = ("" => (("host" => "docspell-restserver", "port" => 7880)))
      }
    }
        accesslog.filename = "/var/log/lighttpd/docspell.log"
}

Expected behavior

Websocket connection working and pushing messages between frontend and backend.

Actual behavior

Websocket connection timed out after 60 seconds after connection had been upgraded. The previous release v0.40.0 didn't run into this issue with same reverse proxy setup.

Logs

2024.02.15 13:09:30:0000 [io-comp...] [ERROR] org.http4s.ember.server.EmberServerBuilderCompanionPlatform - WebSocket connection terminated with exception
java.util.concurrent.TimeoutException: 60 seconds
        at timeout @ org.http4s.ember.core.Util$.timeoutMaybe(Util.scala:106)
        at main$ @ docspell.restserver.Main$.main(Main.scala:14)
        at timeout @ org.http4s.ember.core.Util$.timeoutMaybe(Util.scala:106)
        at timeout @ org.http4s.ember.core.Util$.timeoutMaybe(Util.scala:106)

image

nekrondev avatar Feb 15 '24 12:02 nekrondev

As far as I can see Eike changed from BlazeServerBuilder to EmberServerBuilder implementation using the servers defaults.

https://github.com/eikek/docspell/blob/50dadad48e85d25a8127a3bae2c53110663d90c5/modules/restserver/src/main/scala/docspell/restserver/RestServer.scala#L63

EmberServerBuilder is using a 60 second idle timeout on socket reads that will be raised because there is currently no incoming websocket traffic from the frontend.

https://github.com/http4s/http4s/blob/v0.23.18/server/shared/src/main/scala/org/http4s/server/package.scala#L84

As lighttpd isn't sending pings between http server and REST backend the connection will be idle terminated by backend service after 60 seconds. I'm not sure why this behavior isn't the same as with the previous BlazeServerBuilder initialization that seems to ignore the default idle setting.

nekrondev avatar Feb 15 '24 21:02 nekrondev

To fix this issue the idleTimeout should be user-defined like responseTimeout that can be configured through the startup env vars. The now fixed idle timeout behavior will break reverse proxies that don't send keep alive pings between proxy and backend connection. With the addition of user-defined idleTimeout one can configure a long lasting idle timeout to prevent this.

nekrondev avatar Feb 16 '24 10:02 nekrondev

Actually there is an even better and much more easier solution to this by returning the keep-alive events from client downstream to backend as seen in #2500.

The websocket connection isn't killed after 60s idle timeout with this ping-pong loop.

image

nekrondev avatar Feb 17 '24 11:02 nekrondev

@nekrondev thank you very much for taking a deep look into this! I wasn't aware about the changes in timeouts bewteen blaze and ember.

eikek avatar Feb 18 '24 14:02 eikek