Skip to content

Commit fd5beaa

Browse files
committed
refactor(session): replace recursion with loop and add backoff
This refactor replaces recursion with a loop in the session invoke logic. Additionally, a backoff mechanism has been introduced to prevent frequent restarts from crashing the bot.
1 parent 69e07d4 commit fd5beaa

4 files changed

Lines changed: 37 additions & 32 deletions

File tree

.pre-commit-config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ repos:
1111
- id: check-yaml
1212

1313
- repo: https://github.com/astral-sh/ruff-pre-commit
14-
rev: v0.4.5
14+
rev: v0.4.6
1515
hooks:
1616
- id: ruff-format
1717
- id: ruff

hydrogram/session/session.py

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import contextlib
2323
import logging
2424
import os
25+
from datetime import datetime, timedelta
2526
from hashlib import sha1
2627
from io import BytesIO
2728
from typing import ClassVar
@@ -61,6 +62,7 @@ class Session:
6162
ACKS_THRESHOLD = 10
6263
PING_INTERVAL = 5
6364
STORED_MSG_IDS_MAX_SIZE = 1000 * 2
65+
RECONNECT_THRESHOLD = timedelta(seconds=10)
6466

6567
TRANSPORT_ERRORS: ClassVar = {
6668
404: "auth key not found",
@@ -108,6 +110,8 @@ def __init__(
108110

109111
self.loop = asyncio.get_event_loop()
110112

113+
self.last_reconnect_attempt = None
114+
111115
async def start(self):
112116
while True:
113117
self.connection = Connection(
@@ -189,6 +193,15 @@ async def stop(self):
189193
log.info("Session stopped")
190194

191195
async def restart(self):
196+
now = datetime.now()
197+
if (
198+
self.last_reconnect_attempt
199+
and now - self.last_reconnect_attempt < self.RECONNECT_THRESHOLD
200+
):
201+
log.info("Reconnecting too frequently, sleeping for a while")
202+
await asyncio.sleep(5)
203+
204+
self.last_reconnect_attempt = now
192205
await self.stop()
193206
await self.start()
194207

@@ -406,7 +419,7 @@ async def invoke(
406419

407420
query_name = ".".join(inner_query.QUALNAME.split(".")[1:])
408421

409-
while True:
422+
while retries > 0:
410423
try:
411424
return await self.send(query, timeout=timeout)
412425
except FloodWait as e:
@@ -424,16 +437,17 @@ async def invoke(
424437

425438
await asyncio.sleep(amount)
426439
except (OSError, InternalServerError, ServiceUnavailable) as e:
440+
retries -= 1
427441
if retries == 0:
428-
raise e from None
442+
raise e
429443

430444
(log.warning if retries < 2 else log.info)(
431445
'[%s] Retrying "%s" due to: %s',
432-
Session.MAX_RETRIES - retries + 1,
446+
Session.MAX_RETRIES - retries,
433447
query_name,
434448
str(e) or repr(e),
435449
)
436450

437451
await asyncio.sleep(0.5)
438452

439-
return await self.invoke(query, retries - 1, timeout)
453+
raise TimeoutError("Exceeded maximum number of retries")

hydrogram/types/user_and_chats/chat.py

Lines changed: 17 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -276,37 +276,28 @@ def _parse_chat_chat(client, chat: raw.types.Chat) -> Chat:
276276
@staticmethod
277277
def _parse_channel_chat(client, channel: raw.types.Channel) -> Chat:
278278
peer_id = utils.get_channel_id(channel.id)
279-
restriction_reason = getattr(channel, "restriction_reason", [])
280-
usernames = getattr(channel, "usernames", [])
281279

282280
return Chat(
283281
id=peer_id,
284-
type=enums.ChatType.SUPERGROUP
285-
if getattr(channel, "megagroup", None)
286-
else enums.ChatType.CHANNEL,
287-
is_verified=getattr(channel, "verified", None),
288-
is_restricted=getattr(channel, "restricted", None),
289-
is_creator=getattr(channel, "creator", None),
290-
is_scam=getattr(channel, "scam", None),
291-
is_fake=getattr(channel, "fake", None),
292-
is_forum=getattr(channel, "forum", None),
282+
type=enums.ChatType.SUPERGROUP if channel.megagroup else enums.ChatType.CHANNEL,
283+
is_verified=channel.verified,
284+
is_restricted=channel.restricted,
285+
is_creator=channel.creator,
286+
is_scam=channel.scam,
287+
is_fake=channel.fake,
288+
is_forum=channel.forum,
293289
title=channel.title,
294-
username=getattr(channel, "username", None),
295-
photo=types.ChatPhoto._parse(
296-
client,
297-
getattr(channel, "photo", None),
298-
peer_id,
299-
getattr(channel, "access_hash", 0),
300-
),
301-
restrictions=types.List([types.Restriction._parse(r) for r in restriction_reason])
290+
username=channel.username,
291+
photo=types.ChatPhoto._parse(client, channel.photo, peer_id, channel.access_hash),
292+
restrictions=types.List([
293+
types.Restriction._parse(r) for r in channel.restriction_reason
294+
])
302295
or None,
303-
permissions=types.ChatPermissions._parse(
304-
getattr(channel, "default_banned_rights", None)
305-
),
306-
members_count=getattr(channel, "participants_count", None),
307-
dc_id=getattr(getattr(channel, "photo", None), "dc_id", None),
308-
has_protected_content=getattr(channel, "noforwards", None),
309-
usernames=types.List([types.Username._parse(r) for r in usernames]) or None,
296+
permissions=types.ChatPermissions._parse(channel.default_banned_rights),
297+
members_count=channel.participants_count,
298+
dc_id=getattr(channel.photo, "dc_id", None),
299+
has_protected_content=channel.noforwards,
300+
usernames=types.List([types.Username._parse(r) for r in channel.usernames]) or None,
310301
client=client,
311302
)
312303

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ build-backend = "hatchling.build"
5151
[tool.rye]
5252
managed = true
5353
dev-dependencies = [
54-
"ruff>=0.4.5",
54+
"ruff>=0.4.6",
5555
"pytest>=7.4.3",
5656
"pytest-asyncio>=0.23.2",
5757
"pytest-cov>=4.1.0",

0 commit comments

Comments
 (0)