websocketbinancejava-websocket

Auto reconnect to Binance Websocket after 24 hours


I'm currently experimenting on Binance Websocket (https://binance-docs.github.io/apidocs/spot/en/#websocket-market-streams), streaming the candlestick data for processing.

As documented, the stream will randomly close after 24 hours. What's the best way to continue the session without interruption? I mean disconnect/reconnect after 23 hours so the program will continue without losing its state.

Here's what I did. I'm using the binance-java-api https://github.com/binance-exchange/binance-java-api.

And here's how I connect:

BinanceApiWebSocketClient client =
    BinanceApiClientFactory.newInstance(
            appConfig.getApiKey(),
            appConfig.getApiSecret(),
            appConfig.isUseTestNet(),
            appConfig.isUseTestNet())
        .newWebSocketClient();


client.onCandlestickEvent(cryptoPair.toLowerCase(), getCandlestickInterval(),
    new BinanceApiCallback<>() {
      @Override
      public void onResponse(final CandlestickEvent evt) {}

Solution

  • To solve this issue, I have used a scheduler/timer to reconnect the session every 12 hours. Since I'm using the Quarkus framework, it's readily available.

    Solution: SessionManager class:

    @Singleton
    @Slf4j
    @RequiredArgsConstructor
    public class SessionManagerScheduler {
    
      final BinanceEventHandler binanceEventHandler;
    
      @Scheduled(cron = "0 2 */12 * * ?")
      public void reconnectSession() {
    
        log.info("Keep-Alive: Binance Session Via WebSocket -------------------------");
    
        binanceEventHandler.timeout();
      }
    }
    

    The Binance event handler:

    @ApplicationScoped
    @Slf4j
    @RequiredArgsConstructor
    public class BinanceEventHandler {
    
      final AppConfig appConfig;
      final CandlestickAccumulator candlestickAccumulator;
      final CandlestickMapper candlestickMapper;
    
      private Closeable candleStream = null;
    
      public void start() {
    
        streamCandleEvent();
      }
    
      public void timeout() {
    
        try {
          candleStream.close();
    
          streamCandleEvent();
    
        } catch (IOException e) {
          throw new RuntimeException(e);
        }
      }
    
      private void streamCandleEvent() {
    
        String cryptoPair = String.join(",", appConfig.getCryptoPairs());
    
        log.info("Start listening to cryptoPair={}", cryptoPair);
    
        candleStream = getClient().onCandlestickEvent(cryptoPair.toLowerCase(), getCandlestickInterval(),
            new BinanceApiCallback<>() {
              @Override
              public void onResponse(final CandlestickEvent evt) {
    
                if (!evt.getBarFinal()) {
                  return;
                }
    
                log.debug("Processing cryptoPair={}, event={}", cryptoPair, evt);
    
                Candlestick candlestick = candlestickMapper.asCandleStick(evt);
    
                candlestickAccumulator.processCandlestickEvent(candlestick);
              }
    
              @Override
              public void onFailure(final Throwable cause) {
    
                Application.hasError = true;
                log.error("Fail connecting to Binance API {}", cause.getMessage());
              }
            }
        );
      }
    
      private BinanceApiWebSocketClient getClient() {
    
        return BinanceApiClientFactory.newInstance(
                appConfig.getApiKey(),
                appConfig.getApiSecret(),
                appConfig.isUseTestNet(),
                appConfig.isUseTestNet())
            .newWebSocketClient();
      }
    
      private CandlestickInterval getCandlestickInterval() {
        return CandlestickInterval.valueOf(appConfig.getCandlestickInterval());
      }
    }