go-binance
go-binance copied to clipboard
Issues using keepAlive
I am attempting to use the websocket wrapper to retrieve kline data from multiple symbols. I try to set the WebsocketKeepalive to true and keep the WebsocketTimeout to the default one minute. I successfully receive the kline data, however after 2 minutes sockets are closed.
The error I am given is "use of closed network connection."
Does anyone know where I am going wrong? Or is there a problem with keepAlive?
Any help would be greatly appreciated. Thank you
Below is a sample of my code that I use:
binance.WebsocketKeepalive = true
binance.WebsocketTimeout = time.Second * 1
for {
stop_candle_chan, _, err := binance.WsKlineServe(symbol, klineInterval, tradeKlineDataConsumer, ErrorTradeHandler)
if err != nil {
log.Warn("Was not able to open websoocket for the kline " + symbol + " with error: " + err.Error())
}
<- stop_candle_chan
log.Println("Restarting socket for obtaining minute kline data from coin: " + symbol)
}
@ross-hugo increase the timeout to say binance.WebsocketTimeout = time.Second * 100
I'm having similar issues these days, but with the user stream. I've had a bot running for the past year with the v1 of this library (with the keepalive not being enabled*) with no issues, and since 3 or 4 days ago the app just stops receiving events.
Anyone else can confirm? 😕
* Enabling keepalive didn't help btw
HHmmm.. checking the code I see that the keepalive code actually doesn't make the proper keep alive call, is that correct?
With the proper keepalive call I mean this one: https://github.com/adshao/go-binance/blob/76a69bcd89340b7702ec1ee3b22787910dc44f76/v2/user_stream_service.go#L44
I guess I'll need to properly call keepalive in a separate goroutine so it properly maintains the connection, but then I don't get what's that keepalive method supposed to do in the websocket wsServe method 😕
Edit: The code in this go-binance library is suspiciously similar to this one in stackoverflow: https://stackoverflow.com/a/41482330/407456 I guess it was just copy-pasted, rather than properly check its behavior with binance documentation.
I don't think the problem is keepAlive. I tested it today and for me it worked as expected. When I started a websocket and then manually cut the network connection, the websocket tried to send a PONG after the time set in keepAlive and detected, that the connection was gone.
@elboletaire keepAlive seems to get called here: https://github.com/adshao/go-binance/blob/b7139701aac35c71f32e1a107917b1b7601703c1/v2/websocket.go#L39
@jon4hz check the code of that keepAlive function and you'll see that it does not follow the binance documentation. As I said, I ended up adding a custom goroutine calling NewKeepaliveUserStreamService and passing it the key obtained from the NewStartUserStreamService, which properly fixes the issue.
To be fair, not even binance follows the binance documentation. For example websockets aren't always disconnect after 24h. Sometimes they are valid for a longer timespan, at least that's what I experienced.
If I read that code correctly, it will send a ping to binance in an interval you set via WebsocketTimeout. And since Binance allows unsolicited frames every value under 10min should be fine.
The problem you seem to face is with user streams. The initial question was about a market stream. Market streams don't need to update the listenKey to extend its validity, so that copy-pasted, not perfect keepAlive function should work in this case.
But I agree with you. The method you pointed out doesn't seem to get called anywhere inside the package. Since it's written uppercase I somehow suspect that it's meant to be called from the application and not by the package itself, which seems rather odd.
@elboletaire @jon4hz first off, for this issue, please ignore my comment here https://github.com/adshao/go-binance/issues/206#issuecomment-772557843, I was mixing up the keepAlive (websocket ping) with the keyAlive (user stream).
I see now that you are talking about two different things. And yes, @elboletaire, this is the expected behavior - you are responsible for calling NewKeepaliveUserStreamService with the listenKey. I see no issue here
To be fair, not even binance follows the binance documentation. For example websockets aren't always disconnect after 24h. Sometimes they are valid for a longer timespan, at least that's what I experienced. If I read that code correctly, it will send a ping to binance in an interval you set via WebsocketTimeout. And since Binance allows unsolicited frames every value under 10min should be fine.
I've actually been using this library for months and I know for sure I wasn't using keepalive until I started facing these problems, and it was working perfectly. So yes, I'm aware binance do not follow their own documentation in some cases.
But I agree with you. The method you pointed out doesn't seem to get called anywhere inside the package. Since it's written uppercase I somehow suspect that it's meant to be called from the application and not by the package itself, which seems rather odd.
Exactly. Yeah it's true my case is for user streams and I know it's different and the other case should be fine for non-user streams; but the issue title says "problems with keepAlive", so I started here the conversation. Maybe I should create a specific issue for this case.
I see now that you are talking about two different things. And yes, @elboletaire, this is the expected behavior - you are responsible for calling NewKeepaliveUserStreamService with the listenKey. I see no issue here
The keepAlive inside this user stream service should be a proper call to the NewKeepaliveUserStreamService. I don't see the sense of using the custom keepAlive in there. If there's a "keepAlive" param, it should properly call the NewKeepaliveUserStreamService underneath..
@elboletaire the keepAlive call in the websocket_service is called for all WebSocket subscriptions - that keepAlive is for the WebSocket protocol, to keep the connection open.
But for the user data Websocket service, you still have to keep calling NewKeepaliveUserStreamService in a goroutine to tell Binance you still want data - NewKeepaliveUserStreamService is not a WebSocket protocol dependency, it is Binance requirement to signify you are still interested in the data. If you don't, you will at some point stop receiving data from Binance, even if the WebSocket is still kept open by keepAlive
Exactly. Yeah it's true my case is for user streams and I know it's different and the other case should be fine for non-user streams; but the issue title says "problems with keepAlive", so I started here the conversation. Maybe I should create a specific issue for this case.
I think creating a dedicated issue for that topic would be best.
@en0ma You are right but since this is a wrapper for that exact API there would be nothing wrong with doing such keepAlive (keyAlive) calls under the hood, too. And if not, @adshao could at least point that out in the docs.
Exactly. Yeah it's true my case is for user streams and I know it's different and the other case should be fine for non-user streams; but the issue title says "problems with keepAlive", so I started here the conversation. Maybe I should create a specific issue for this case.
I think creating a dedicated issue for that topic would be best.
@en0ma You are right but since this is a wrapper for that exact API there would be nothing wrong with doing such keepAlive (keyAlive) calls under the hood, too.
Yeah, a new method (WsUserDataServeWithKeepAlive) could be added to do it, or the doc can be improved to show how to use NewKeepaliveUserStreamService with WsUserDataServe
Any update on this? Do I have to manually write a ticker and request timer to send keepalive API request with the listenkey once every hour?
//Edit:
I found KeepaliveUserStreamService - so this at least takes care of the requests but why doesn't the SDK automatically handle keepalives in the websocket client through a time.Ticker in a goroutine? Or at least make it very much obvious in the documentation that you are required to create a ticker yourself and repeatedly call KeepaliveUserStreamService.Do every Hour
Hi, thanks for the update. Would you like to submit a pull request for this change?
Any update on this? Do I have to manually write a ticker and request timer to send keepalive API request with the listenkey once every hour?
//Edit:
I found
KeepaliveUserStreamService- so this at least takes care of the requests but why doesn't the SDK automatically handle keepalives in the websocket client through atime.Tickerin a goroutine? Or at least make it very much obvious in the documentation that you are required to create a ticker yourself and repeatedly callKeepaliveUserStreamService.Doevery Hour
can you show some example to use this please