How in BinanceSocketManager to handle the connection break correctly?
Question:
Good time of the day, tell me I can’t beat the next disease in any way. I receive the found ohlcvs over the WS channel in real time. From time to time, my Internet connection disappears, sometimes when WS is connected for too long, Binance itself breaks the connection. I want to make sure that in case of disconnection, my program tries to connect again. To do this, I made a Try except block – if something bad happens in it, I just try to call the connect function again. It seems to sound logical and should work. However, during the test I get an error
Max reconnections 5 reached: CANCEL read_loop
At first, this error looks like I managed to catch it, but then the call stack follows and the program crashes
Traceback (most recent call last):
File "/home/master/PycharmProjects/PROJECT/venv/lib/python3.10/site-packages/aiohttp/connector.py", line 1155, in _create_direct_connection
hosts = await asyncio.shield(host_resolved)
File "/home/master/PycharmProjects/PROJECT/venv/lib/python3.10/site-packages/aiohttp/connector.py", line 874, in _resolve_host
addrs = await self._resolver.resolve(host, port, family=self._family)
File "/home/master/PycharmProjects/PROJECT/venv/lib/python3.10/site-packages/aiohttp/resolver.py", line 33, in resolve
infos = await self._loop.getaddrinfo(
File "/usr/lib/python3.10/asyncio/base_events.py", line 863, in getaddrinfo
return await self.run_in_executor(
File "/usr/lib/python3.10/concurrent/futures/thread.py", line 58, in run
result = self.fn(*self.args, **self.kwargs)
File "/usr/lib/python3.10/socket.py", line 955, in getaddrinfo
for res in _socket.getaddrinfo(host, port, family, type, proto, flags):
socket.gaierror: [Errno -3] Temporary failure in name resolution
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/home/master/PycharmProjects/PROJECT/main.py", line 43, in <module>
loop.run_until_complete(main())
File "/usr/lib/python3.10/asyncio/base_events.py", line 649, in run_until_complete
return future.result()
File "/home/master/PycharmProjects/PROJECT/main.py", line 35, in main
await asyncio.gather(stream.live_kline(), interrupt_sys.listen(), display(memory))
File "/home/master/PycharmProjects/PROJECT/kernel/market/stream.py", line 45, in live_kline
await self.connect()
File "/home/master/PycharmProjects/PROJECT/kernel/market/stream.py", line 21, in connect
self.__client = await AsyncClient.create(self.config.system_api_public_key,
File "/home/master/PycharmProjects/PROJECT/venv/lib/python3.10/site-packages/binance/client.py", line 7866, in create
await self.ping()
File "/home/master/PycharmProjects/PROJECT/venv/lib/python3.10/site-packages/binance/client.py", line 7988, in ping
return await self._get('ping', version=self.PRIVATE_API_VERSION)
File "/home/master/PycharmProjects/PROJECT/venv/lib/python3.10/site-packages/binance/client.py", line 7953, in _get
return await self._request_api('get', path, signed, version, **kwargs)
File "/home/master/PycharmProjects/PROJECT/venv/lib/python3.10/site-packages/binance/client.py", line 7916, in _request_api
return await self._request(method, uri, signed, **kwargs)
File "/home/master/PycharmProjects/PROJECT/venv/lib/python3.10/site-packages/binance/client.py", line 7897, in _request
async with getattr(self.session, method)(uri, **kwargs) as response:
File "/home/master/PycharmProjects/PROJECT/venv/lib/python3.10/site-packages/aiohttp/client.py", line 1141, in __aenter__
self._resp = await self._coro
File "/home/master/PycharmProjects/PROJECT/venv/lib/python3.10/site-packages/aiohttp/client.py", line 536, in _request
conn = await self._connector.connect(
File "/home/master/PycharmProjects/PROJECT/venv/lib/python3.10/site-packages/aiohttp/connector.py", line 540, in connect
proto = await self._create_connection(req, traces, timeout)
File "/home/master/PycharmProjects/PROJECT/venv/lib/python3.10/site-packages/aiohttp/connector.py", line 901, in _create_connection
_, proto = await self._create_direct_connection(req, traces, timeout)
File "/home/master/PycharmProjects/PROJECT/venv/lib/python3.10/site-packages/aiohttp/connector.py", line 1169, in _create_direct_connection
raise ClientConnectorError(req.connection_key, exc) from exc
aiohttp.client_exceptions.ClientConnectorError: Cannot connect to host api.binance.com:443 ssl:default [Temporary failure in name resolution]
Process finished with exit code 1
Tell me what’s the matter – it feels like "try except" just doesn’t work. Or is there something going on that I don’t understand
How do I test? I just launch the application and then turn off the network card for more than 1 minute to simulate a connection break.
import asyncio
from binance import Client, AsyncClient, ThreadedWebsocketManager, ThreadedDepthCacheManager, BinanceSocketManager
class Stream:
def __init__(self):
self.__ts = None
self.__chanel_name = None
self.__bsm = None
self.__client = None
async def connect(self):
self.__client = await AsyncClient.create('','')
self.__bsm = BinanceSocketManager(self.__client, 60)
self.__chanel_name = 'btcusdt@kline_1m'
self.__ts = self.__bsm.futures_multiplex_socket([self.__chanel_name])
async def live_kline(self):
while True:
try:
async with self.__ts as tscm:
while True:
stream = await tscm.recv()
# Updates order statuses in real time
if stream['stream'] == self.__chanel_name:
Stream.process_message(stream)
except Exception as e:
print(f"An error occurred: {e}. Reconnecting...")
await self.__client.close_connection()
await asyncio.sleep(1)
await self.connect()
continue
@staticmethod
def process_message(msg: dict):
pass
async def main():
stream = Stream()
await stream.connect()
await asyncio.gather(stream.live_kline())
loop.stop()
if __name__ == '__main__':
loop = asyncio.new_event_loop()
loop.run_until_complete(main())
Answers:
"Max reconnections 5 reached: CANCEL read_loop," the error you’re seeing, is reported by the binance
library when it hits the maximum number of reconnection attempts, which is set to 5 by default. Even if you’re using a try-except block to detect problems and attempt reconnection, it looks that the library is still reaching its internal limit. You may avoid this constraint and elegantly manage reconnections by implementing a custom reconnection mechanism and handling the reconnection count yourself. Here’s a revised version of your code that fixes the problem:
import asyncio
from binance import AsyncClient, BinanceSocketManager
class Stream:
def __init__(self):
self.__ts = None
self.__chanel_name = None
self.__bsm = None
self.__client = None
self.__reconnection_attempts = 0
async def connect(self):
self.__client = await AsyncClient.create('your_api_key', 'your_api_secret')
self.__bsm = BinanceSocketManager(self.__client, 60)
self.__chanel_name = 'btcusdt@kline_1m'
self.__ts = self.__bsm.futures_multiplex_socket([self.__chanel_name])
async def live_kline(self):
while True:
try:
async with self.__ts as tscm:
while True:
stream = await tscm.recv()
# Updates order statuses in real time
if stream['stream'] == self.__chanel_name:
Stream.process_message(stream)
self.__reconnection_attempts = 0 # Reset reconnection attempts on successful connection
except Exception as e:
print(f"An error occurred: {e}. Reconnecting...")
await self.__client.close_connection()
await asyncio.sleep(1)
await self.connect()
self.__reconnection_attempts += 1
if self.__reconnection_attempts >= 5:
print("Max reconnection attempts reached. Exiting.")
break
@staticmethod
def process_message(msg: dict):
pass
async def main():
stream = Stream()
await stream.connect()
await asyncio.gather(stream.live_kline())
if __name__ == '__main__':
loop = asyncio.new_event_loop()
loop.run_until_complete(main())
To keep track of reconnection attempts, I’ve added a variable called self.__reconnection_attempts
. If the limit number of reconnecting tries (5 in this example) is reached after each reconnection attempt, the software will display a notification and quit the loop, stopping unending reconnection attempts. This customized reconnection approach should allow your software to smoothly manage disconnections while adhering to the maximum reconnection restriction.
Good time of the day, tell me I can’t beat the next disease in any way. I receive the found ohlcvs over the WS channel in real time. From time to time, my Internet connection disappears, sometimes when WS is connected for too long, Binance itself breaks the connection. I want to make sure that in case of disconnection, my program tries to connect again. To do this, I made a Try except block – if something bad happens in it, I just try to call the connect function again. It seems to sound logical and should work. However, during the test I get an error
Max reconnections 5 reached: CANCEL read_loop
At first, this error looks like I managed to catch it, but then the call stack follows and the program crashes
Traceback (most recent call last):
File "/home/master/PycharmProjects/PROJECT/venv/lib/python3.10/site-packages/aiohttp/connector.py", line 1155, in _create_direct_connection
hosts = await asyncio.shield(host_resolved)
File "/home/master/PycharmProjects/PROJECT/venv/lib/python3.10/site-packages/aiohttp/connector.py", line 874, in _resolve_host
addrs = await self._resolver.resolve(host, port, family=self._family)
File "/home/master/PycharmProjects/PROJECT/venv/lib/python3.10/site-packages/aiohttp/resolver.py", line 33, in resolve
infos = await self._loop.getaddrinfo(
File "/usr/lib/python3.10/asyncio/base_events.py", line 863, in getaddrinfo
return await self.run_in_executor(
File "/usr/lib/python3.10/concurrent/futures/thread.py", line 58, in run
result = self.fn(*self.args, **self.kwargs)
File "/usr/lib/python3.10/socket.py", line 955, in getaddrinfo
for res in _socket.getaddrinfo(host, port, family, type, proto, flags):
socket.gaierror: [Errno -3] Temporary failure in name resolution
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/home/master/PycharmProjects/PROJECT/main.py", line 43, in <module>
loop.run_until_complete(main())
File "/usr/lib/python3.10/asyncio/base_events.py", line 649, in run_until_complete
return future.result()
File "/home/master/PycharmProjects/PROJECT/main.py", line 35, in main
await asyncio.gather(stream.live_kline(), interrupt_sys.listen(), display(memory))
File "/home/master/PycharmProjects/PROJECT/kernel/market/stream.py", line 45, in live_kline
await self.connect()
File "/home/master/PycharmProjects/PROJECT/kernel/market/stream.py", line 21, in connect
self.__client = await AsyncClient.create(self.config.system_api_public_key,
File "/home/master/PycharmProjects/PROJECT/venv/lib/python3.10/site-packages/binance/client.py", line 7866, in create
await self.ping()
File "/home/master/PycharmProjects/PROJECT/venv/lib/python3.10/site-packages/binance/client.py", line 7988, in ping
return await self._get('ping', version=self.PRIVATE_API_VERSION)
File "/home/master/PycharmProjects/PROJECT/venv/lib/python3.10/site-packages/binance/client.py", line 7953, in _get
return await self._request_api('get', path, signed, version, **kwargs)
File "/home/master/PycharmProjects/PROJECT/venv/lib/python3.10/site-packages/binance/client.py", line 7916, in _request_api
return await self._request(method, uri, signed, **kwargs)
File "/home/master/PycharmProjects/PROJECT/venv/lib/python3.10/site-packages/binance/client.py", line 7897, in _request
async with getattr(self.session, method)(uri, **kwargs) as response:
File "/home/master/PycharmProjects/PROJECT/venv/lib/python3.10/site-packages/aiohttp/client.py", line 1141, in __aenter__
self._resp = await self._coro
File "/home/master/PycharmProjects/PROJECT/venv/lib/python3.10/site-packages/aiohttp/client.py", line 536, in _request
conn = await self._connector.connect(
File "/home/master/PycharmProjects/PROJECT/venv/lib/python3.10/site-packages/aiohttp/connector.py", line 540, in connect
proto = await self._create_connection(req, traces, timeout)
File "/home/master/PycharmProjects/PROJECT/venv/lib/python3.10/site-packages/aiohttp/connector.py", line 901, in _create_connection
_, proto = await self._create_direct_connection(req, traces, timeout)
File "/home/master/PycharmProjects/PROJECT/venv/lib/python3.10/site-packages/aiohttp/connector.py", line 1169, in _create_direct_connection
raise ClientConnectorError(req.connection_key, exc) from exc
aiohttp.client_exceptions.ClientConnectorError: Cannot connect to host api.binance.com:443 ssl:default [Temporary failure in name resolution]
Process finished with exit code 1
Tell me what’s the matter – it feels like "try except" just doesn’t work. Or is there something going on that I don’t understand
How do I test? I just launch the application and then turn off the network card for more than 1 minute to simulate a connection break.
import asyncio
from binance import Client, AsyncClient, ThreadedWebsocketManager, ThreadedDepthCacheManager, BinanceSocketManager
class Stream:
def __init__(self):
self.__ts = None
self.__chanel_name = None
self.__bsm = None
self.__client = None
async def connect(self):
self.__client = await AsyncClient.create('','')
self.__bsm = BinanceSocketManager(self.__client, 60)
self.__chanel_name = 'btcusdt@kline_1m'
self.__ts = self.__bsm.futures_multiplex_socket([self.__chanel_name])
async def live_kline(self):
while True:
try:
async with self.__ts as tscm:
while True:
stream = await tscm.recv()
# Updates order statuses in real time
if stream['stream'] == self.__chanel_name:
Stream.process_message(stream)
except Exception as e:
print(f"An error occurred: {e}. Reconnecting...")
await self.__client.close_connection()
await asyncio.sleep(1)
await self.connect()
continue
@staticmethod
def process_message(msg: dict):
pass
async def main():
stream = Stream()
await stream.connect()
await asyncio.gather(stream.live_kline())
loop.stop()
if __name__ == '__main__':
loop = asyncio.new_event_loop()
loop.run_until_complete(main())
"Max reconnections 5 reached: CANCEL read_loop," the error you’re seeing, is reported by the binance
library when it hits the maximum number of reconnection attempts, which is set to 5 by default. Even if you’re using a try-except block to detect problems and attempt reconnection, it looks that the library is still reaching its internal limit. You may avoid this constraint and elegantly manage reconnections by implementing a custom reconnection mechanism and handling the reconnection count yourself. Here’s a revised version of your code that fixes the problem:
import asyncio
from binance import AsyncClient, BinanceSocketManager
class Stream:
def __init__(self):
self.__ts = None
self.__chanel_name = None
self.__bsm = None
self.__client = None
self.__reconnection_attempts = 0
async def connect(self):
self.__client = await AsyncClient.create('your_api_key', 'your_api_secret')
self.__bsm = BinanceSocketManager(self.__client, 60)
self.__chanel_name = 'btcusdt@kline_1m'
self.__ts = self.__bsm.futures_multiplex_socket([self.__chanel_name])
async def live_kline(self):
while True:
try:
async with self.__ts as tscm:
while True:
stream = await tscm.recv()
# Updates order statuses in real time
if stream['stream'] == self.__chanel_name:
Stream.process_message(stream)
self.__reconnection_attempts = 0 # Reset reconnection attempts on successful connection
except Exception as e:
print(f"An error occurred: {e}. Reconnecting...")
await self.__client.close_connection()
await asyncio.sleep(1)
await self.connect()
self.__reconnection_attempts += 1
if self.__reconnection_attempts >= 5:
print("Max reconnection attempts reached. Exiting.")
break
@staticmethod
def process_message(msg: dict):
pass
async def main():
stream = Stream()
await stream.connect()
await asyncio.gather(stream.live_kline())
if __name__ == '__main__':
loop = asyncio.new_event_loop()
loop.run_until_complete(main())
To keep track of reconnection attempts, I’ve added a variable called self.__reconnection_attempts
. If the limit number of reconnecting tries (5 in this example) is reached after each reconnection attempt, the software will display a notification and quit the loop, stopping unending reconnection attempts. This customized reconnection approach should allow your software to smoothly manage disconnections while adhering to the maximum reconnection restriction.