Golang server default timeout with (long polling) server-sent event calls. The call is closed, how to maintain it open?

huangapple go评论112阅读模式
英文:

Golang server default timeout with (long polling) server-sent event calls. The call is closed, how to maintain it open?

问题

我正在使用Golang中的这个令人惊奇的SSE服务器(https://github.com/r3labs/sse)在Heroku上。

那里有一个超时限制:https://devcenter.heroku.com/articles/request-timeout#long-polling-and-streaming-responses:

如果您正在发送流式响应,例如使用服务器发送事件(server-sent events),您需要检测客户端何时挂断,并确保您的应用服务器及时关闭连接。如果服务器在55秒内保持连接打开而没有发送任何数据,您将会看到请求超时。

我知道在WebSocket世界中有保持活动的ping的概念。

我正在尝试使用以下代码:

go func() {
  for range time.Tick(time.Second * 1) {
    fmt.Println("一秒钟")
    sseServer.Publish("test", &sse.Event{Data: []byte("ping")})
  }
}()

使用类似以下的简单服务器:

httpServer := &http.Server{
  //...
  ReadTimeout:  "10s",
  WriteTimeout: "10s",
}

但是它不起作用。调用在10秒后(和10个ping)被关闭。

我认为在Heroku上也会失败。

我错在哪里?

我们能否仅更改这些SSE调用的超时时间?

还有其他方法吗?

更新

我不需要准确检测断开连接的客户端,我完全不关心。我正在使用它来在服务器上发生某些事件时刷新仪表板。

对于这么简单的事情,我更倾向于不使用WebSocket。

我认为我没有解释清楚,因为我希望使用ping不是为了检测断开连接的客户端,而是因为我希望连接不会中断(就像在Heroku上发生的情况一样)。

当前情况

本地

如果我在Windows上完全删除ReadTimeout字段,但也在Docker Linux容器上删除它,连接不会停止,一切正常工作。

在Heroku上

由于在Heroku上,由于我在第一篇帖子中告诉您的超时时间,连接每55秒断开一次,我尝试了那个循环和那个非常简单的代码,它起作用了:SSE调用不再关闭!

剩下的问题

  1. 如何为所有其他调用(非SSE)设置默认的ReadTimeout?我认为设置默认的ReadTimeout是最佳实践。

如何做到?

英文:

I'm using this amazing SSE Server in Golang (https://github.com/r3labs/sse) on Heroku.

There is a timeout limit there: https://devcenter.heroku.com/articles/request-timeout#long-polling-and-streaming-responses:

> If you’re sending a streaming response, such as with server-sent events, you’ll need to detect when the client has hung up, and make sure your app server closes the connection promptly. If the server keeps the connection open for 55 seconds without sending any data, you’ll see a request timeout.

I know in the WebSocket world there is the concept of Keep-Alive ping.

I'm trying with this code:

go func() {
  for range time.Tick(time.Second * 1) {
    fmt.Println("a second")
    sseServer.Publish("test", &sse.Event{Data: []byte("ping")})
  }
}()

using a simple server like this:

httpServer := &http.Server{
  //...
  ReadTimeout:  "10s",
  WriteTimeout: "10s",
}

but it doesn't work. The call is closed after 10 seconds (and 10 pings).

I think it will fail on Heroku too.

Where am I wrong?

Can we change the timeout for these SSE calls only?

Is there another way?

UPDATE

I don't need accurate detection of disconnected client, I don't care at all. I'm using it to refresh a dashboard when something happens on server.

I prefer not to use WebSocket for something so easy.

I think I have not explained myself well, because I would like to use ping not so much for detecting disconnected clients but because I would like the connection not to be interrupted (as is happening on Heroku).

THE SITUATION RIGHT NOW

LOCALLY

If I remove the ReadTimeout field totally on Windows but also on Docker linux container the connection does not stop and everything works fine.

ON HEROKU

Since on Heroku the connection drops every 55 seconds for that timeout I told you in the first post I tried that loop with that very simple code and it works: the SSE calls are not closed anymore!

THE REMAINING ISSUE

  1. How to have in any case a default ReadTimeout for all other calls (not SSE); I think it's best practice to set a default ReadTimeout.

How to do?

答案1

得分: 1

你不需要设置ReadTimeout;服务器在初始的EventSource/Server Sent Events (SSE)连接之后将永远不会从客户端读取任何内容。

因此,在SSE连接中设置默认的读取超时时间并不是一个最佳实践,因为该读取超时时间总是会触发。你永远无法通过初始的SSE GET请求发送更多的数据。

你应该将SSE视为一个从不关闭的GET请求,因为实际上就是这样。这意味着它在大多数代理服务器上运行良好,在代理服务器不支持的情况下(代理服务器应用自己的超时时间),客户端会自动重新连接,这实际上是一个非常好的功能,在Websockets中找不到(尽管大多数Websockets客户端库都实现了这个功能)。

你可能想阅读一下这篇文章,了解一些关于SSE的优点和缺点:https://www.smashingmagazine.com/2018/02/sse-websockets-data-flow-http2/

至于你的另一个问题,你可能正在寻找一个HTTP路由库,它允许你对某些GET请求应用超时,而对其他请求不应用超时,但问题是为什么要这样做;如果你试图防止资源耗尽,你应该在所有端点上均匀地应用这种保护。

英文:

You do not need the ReadTimeout; the server will never read anything from the client after the initial EventSource/Server Sent Events (SSE) connection.

Thus, it is not a best practice to set a default read timeout with an SSE connection, because that read timeout will always get hit. You can't ever send more data back up through the initial SSE GET request.

You should think about SSE as basically a GET request that simply never closes, because that's almost literally what it is. That means that it works great through most proxy servers, and where it doesn't (where the proxy server applies its own timeouts), the client side will automatically reconnect, which is actually a very nice feature that is not found in websockets (although most websocket client libraries do implement it).

You might want to read through this article to learn some more of the great (and not-so-great) things about SSE: https://www.smashingmagazine.com/2018/02/sse-websockets-data-flow-http2/

With regards to your other question, you're probably looking for your HTTP routing library that will allow you to apply timeouts to some GET requests, and not others, but the question is why; if you are trying to protect from a resource drain, you should apply that protection evenly across all endpoints.

huangapple
  • 本文由 发表于 2021年11月6日 21:50:42
  • 转载请务必保留本文链接:https://go.coder-hub.com/69864592.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定