2
2
import json
3
3
import websockets
4
4
from loguru import logger
5
+ from tenacity import retry , retry_if_exception_type , wait_exponential
5
6
import time
6
7
7
- from pusher .config import Config
8
+ from pusher .config import Config , STALE_TIMEOUT_SECONDS
9
+ from pusher .exception import StaleConnection
8
10
from pusher .price_state import PriceState , PriceUpdate
9
11
10
12
# This will be in config, but note here.
@@ -32,14 +34,13 @@ def get_subscribe_request(self, asset):
32
34
async def subscribe_all (self ):
33
35
await asyncio .gather (* (self .subscribe_single (hyperliquid_ws_url ) for hyperliquid_ws_url in self .hyperliquid_ws_urls ))
34
36
37
+ @retry (
38
+ retry = retry_if_exception_type ((StaleConnection , websockets .ConnectionClosed )),
39
+ wait = wait_exponential (multiplier = 1 , min = 1 , max = 10 ),
40
+ reraise = True ,
41
+ )
35
42
async def subscribe_single (self , url ):
36
- while True :
37
- try :
38
- await self .subscribe_single_inner (url )
39
- except websockets .ConnectionClosed :
40
- logger .error ("Connection to {} closed; retrying" , url )
41
- except Exception as e :
42
- logger .exception ("Error on {}: {}" , url , e )
43
+ return await self .subscribe_single_inner (url )
43
44
44
45
async def subscribe_single_inner (self , url ):
45
46
async with websockets .connect (url ) as ws :
@@ -48,8 +49,9 @@ async def subscribe_single_inner(self, url):
48
49
logger .info ("Sent subscribe request to {}" , url )
49
50
50
51
# listen for updates
51
- async for message in ws :
52
+ while True :
52
53
try :
54
+ message = await asyncio .wait_for (ws .recv (), timeout = STALE_TIMEOUT_SECONDS )
53
55
data = json .loads (message )
54
56
channel = data .get ("channel" , None )
55
57
if not channel :
@@ -62,8 +64,14 @@ async def subscribe_single_inner(self, url):
62
64
self .parse_hyperliquid_ws_message (data )
63
65
else :
64
66
logger .error ("Received unknown channel: {}" , channel )
67
+ except asyncio .TimeoutError :
68
+ raise StaleConnection (f"No messages in { STALE_TIMEOUT_SECONDS } seconds, reconnecting..." )
69
+ except websockets .ConnectionClosed :
70
+ raise
65
71
except json .JSONDecodeError as e :
66
72
logger .error ("Failed to decode JSON message: {} error: {}" , message , e )
73
+ except Exception as e :
74
+ logger .error ("Unexpected exception: {}" , e )
67
75
68
76
def parse_hyperliquid_ws_message (self , message ):
69
77
try :
0 commit comments