66from collections import deque
77from typing import Optional , Set , Dict
88
9- import grpc
109
11- import ydb
1210from .. import _apis , issues , RetrySettings
1311from ..aio import Driver
1412from ..issues import (
@@ -53,7 +51,7 @@ class ReaderReconnector:
5351
5452 _state_changed : asyncio .Event
5553 _stream_reader : Optional ["ReaderStream" ]
56- _first_error : asyncio .Future [ydb . Error ]
54+ _first_error : asyncio .Future [YdbError ]
5755
5856 def __init__ (self , driver : Driver , settings : PublicReaderSettings ):
5957 self ._settings = settings
@@ -71,11 +69,10 @@ async def _connection_loop(self):
7169 while True :
7270 try :
7371 self ._stream_reader = await ReaderStream .create (self ._driver , self ._settings )
72+ attempt = 0
7473 self ._state_changed .set ()
75- self ._stream_reader ._state_changed .wait ()
76- except Exception as err :
77- # todo reset attempts when connection established
78-
74+ await self ._stream_reader .wait_error ()
75+ except issues .Error as err :
7976 retry_info = check_retriable_error (err , self ._settings ._retry_settings (), attempt )
8077 if not retry_info .is_retriable :
8178 self ._set_first_error (err )
@@ -90,8 +87,11 @@ async def wait_message(self):
9087 raise self ._first_error .result ()
9188
9289 if self ._stream_reader is not None :
93- await self ._stream_reader .wait_messages ()
94- return
90+ try :
91+ await self ._stream_reader .wait_messages ()
92+ return
93+ except YdbError :
94+ pass # handle errors in reconnection loop
9595
9696 await self ._state_changed .wait ()
9797 self ._state_changed .clear ()
@@ -114,6 +114,7 @@ def _set_first_error(self, err: issues.Error):
114114 # skip if already has result
115115 pass
116116
117+
117118class ReaderStream :
118119 _token_getter : Optional [TokenGetterFuncType ]
119120 _session_id : str
@@ -126,7 +127,7 @@ class ReaderStream:
126127 _state_changed : asyncio .Event
127128 _closed : bool
128129 _message_batches : typing .Deque [PublicBatch ]
129- first_error : asyncio .Future [YdbError ]
130+ _first_error : asyncio .Future [YdbError ]
130131
131132 def __init__ (self , settings : PublicReaderSettings ):
132133 self ._token_getter = settings ._token_getter
@@ -139,7 +140,7 @@ def __init__(self, settings: PublicReaderSettings):
139140
140141 self ._state_changed = asyncio .Event ()
141142 self ._closed = False
142- self .first_error = asyncio .get_running_loop ().create_future ()
143+ self ._first_error = asyncio .get_running_loop ().create_future ()
143144 self ._message_batches = deque ()
144145
145146 @staticmethod
@@ -174,6 +175,9 @@ async def _start(self, stream: IGrpcWrapperAsyncIO, init_message: StreamReadMess
174175 read_messages_task = asyncio .create_task (self ._read_messages_loop (stream ))
175176 self ._background_tasks .add (read_messages_task )
176177
178+ async def wait_error (self ):
179+ raise await self ._first_error
180+
177181 async def wait_messages (self ):
178182 while True :
179183 if self ._get_first_error () is not None :
@@ -317,17 +321,17 @@ def _read_response_to_batches(self, message: StreamReadMessage.ReadResponse) ->
317321 batches [- 1 ]._bytes_size += additional_bytes_to_last_batch
318322 return batches
319323
320- def _set_first_error (self , err ):
324+ def _set_first_error (self , err : ydb . Error ):
321325 try :
322- self .first_error .set_result (err )
326+ self ._first_error .set_result (err )
323327 self ._state_changed .set ()
324328 except asyncio .InvalidStateError :
325329 # skip later set errors
326330 pass
327331
328- def _get_first_error (self ):
329- if self .first_error .done ():
330- return self .first_error .result ()
332+ def _get_first_error (self ) -> Optional [ ydb . Error ] :
333+ if self ._first_error .done ():
334+ return self ._first_error .result ()
331335 else :
332336 return None
333337
0 commit comments