Skip to content

Commit 5ce0fd4

Browse files
committed
refactor(connection, session, tcp): optimize connection parameters and enhance restart logic
1 parent 4745dcc commit 5ce0fd4

3 files changed

Lines changed: 25 additions & 9 deletions

File tree

pyrogram/connection/connection.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@
3030

3131
class Connection:
3232
MAX_CONNECTION_ATTEMPTS = -1
33-
INITIAL_BACKOFF = 1
34-
MAX_BACKOFF = 30
33+
INITIAL_BACKOFF = 0.5
34+
MAX_BACKOFF = 3
3535

3636
def __init__(
3737
self,

pyrogram/connection/transport/tcp/tcp.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ class ProxyDict(TypedDict):
3939

4040

4141
class TCP:
42-
TIMEOUT = 10
42+
TIMEOUT = 6
4343

4444
def __init__(
4545
self,
@@ -181,8 +181,7 @@ async def send(self, data: bytes, wait_for_marker: bool = True) -> None:
181181

182182
async with self.lock:
183183
if self.writer is None or self.writer.is_closing():
184-
log.debug("Send called but writer is None or closing")
185-
return None
184+
raise OSError("Connection is closed")
186185

187186
log.debug("Sending %d bytes", len(data))
188187
try:

pyrogram/session/session.py

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ class Session:
8888
ACKS_THRESHOLD = 10
8989
PING_INTERVAL = 5
9090
RETRY_DELAY = 1
91-
MAX_RESTART_DELAY = 30
91+
MAX_RESTART_DELAY = 10
9292
STORED_MSG_IDS_MAX_SIZE = 1000 * 2
9393
CRYPTO_EXECUTOR_WORKERS = 1
9494
MAX_CONSECUTIVE_IGNORED = 30
@@ -144,6 +144,7 @@ def __init__(
144144
self.fatal_error: Optional[BaseException] = None
145145

146146
self._consecutive_restarts: int = 0
147+
self._restart_generation: int = 0
147148

148149
@property
149150
def _log_prefix(self) -> str:
@@ -275,10 +276,15 @@ async def stop(self) -> None:
275276
await self._invoke_handler(self.client.disconnect_handler)
276277

277278
async def restart(self) -> None:
279+
# Capture generation BEFORE acquiring the lock (no await in between, so
280+
# no interleaving in asyncio). If another restart completes while we
281+
# wait for the lock, the generation will have advanced and we can skip.
282+
expected_gen = self._restart_generation
283+
278284
async with self.restart_lock:
279-
# Skip if another restart already completed while we waited for the lock
280-
if self._state == SessionState.STARTED:
281-
log.debug("[%s] Session already restarted, skipping redundant restart", self._log_prefix)
285+
if self._restart_generation != expected_gen:
286+
log.debug("[%s] Skipping redundant restart (generation %d -> %d)",
287+
self._log_prefix, expected_gen, self._restart_generation)
282288
return
283289

284290
if self.stored_msg_ids:
@@ -298,12 +304,23 @@ async def restart(self) -> None:
298304
await asyncio.sleep(delay)
299305

300306
self._consecutive_restarts += 1
307+
self._restart_generation += 1
301308

302309
self.session_id = os.urandom(8)
303310
self.msg_factory = MsgFactory(self.client)
304311

305312
await self.start()
306313

314+
# After lock released: sync update state so the server resumes pushing
315+
# updates on the new session. Only needed for the main session.
316+
if self.is_started.is_set() and not self.is_cdn and not self.is_media:
317+
try:
318+
await self.client.invoke(raw.functions.updates.GetState())
319+
log.info("[%s] Post-restart update state synced", self._log_prefix)
320+
except Exception as e:
321+
log.warning("[%s] Post-restart update sync failed: %s - %s",
322+
self._log_prefix, type(e).__name__, e)
323+
307324
def _fail_pending_results(self, error: BaseException) -> None:
308325
for result in self.results.values():
309326
if result.value is None:

0 commit comments

Comments
 (0)