Skip to content

Commit d70811b

Browse files
committed
Fix infinite loop when invoking on update handlers (fix #336)
Every update that hadn't been acknowledged on the main connection yet would be resent on any new connection. These new connections are made temporary when invoking anything from any thread that's not the main thread. It would also process all the updates, hence, Telegram would be resending these not-acknowledged updates to the temporary connection, and the updates would be processed again, then the update handler would react to the duplicated updates over and over. To fix this, simply don't process updates on the temporary thread at all. With this reasoning, if we don't acknowledge updates on the temporary connections, Telegram will resend them on the main connection, so we should not lose any.
1 parent 2782a08 commit d70811b

File tree

1 file changed

+15
-4
lines changed

1 file changed

+15
-4
lines changed

Diff for: telethon/telegram_bare_client.py

+15-4
Original file line numberDiff line numberDiff line change
@@ -432,9 +432,18 @@ def __call__(self, *requests, retries=5):
432432
on_main_thread = threading.get_ident() == self._main_thread_ident
433433
if on_main_thread or self._on_read_thread():
434434
sender = self._sender
435+
update_state = self.updates
435436
else:
436437
sender = self._sender.clone()
437438
sender.connect()
439+
# We're on another connection, Telegram will resend all the
440+
# updates that we haven't acknowledged (potentially entering
441+
# an infinite loop if we're calling this in response to an
442+
# update event, as it would be received again and again). So
443+
# to avoid this we will simply not process updates on these
444+
# new temporary connections, as they will be sent and later
445+
# acknowledged over the main connection.
446+
update_state = None
438447

439448
# We should call receive from this thread if there's no background
440449
# thread reading or if the server disconnected us and we're trying
@@ -447,7 +456,9 @@ def __call__(self, *requests, retries=5):
447456
if self._background_error and on_main_thread:
448457
raise self._background_error
449458

450-
result = self._invoke(sender, call_receive, *requests)
459+
result = self._invoke(
460+
sender, call_receive, update_state, *requests
461+
)
451462
if result is not None:
452463
return result
453464

@@ -459,7 +470,7 @@ def __call__(self, *requests, retries=5):
459470
# Let people use client.invoke(SomeRequest()) instead client(...)
460471
invoke = __call__
461472

462-
def _invoke(self, sender, call_receive, *requests):
473+
def _invoke(self, sender, call_receive, update_state, *requests):
463474
try:
464475
# Ensure that we start with no previous errors (i.e. resending)
465476
for x in requests:
@@ -479,7 +490,7 @@ def _invoke(self, sender, call_receive, *requests):
479490
)
480491
else:
481492
while not all(x.confirm_received.is_set() for x in requests):
482-
sender.receive(update_state=self.updates)
493+
sender.receive(update_state=update_state)
483494

484495
except TimeoutError:
485496
pass # We will just retry
@@ -526,7 +537,7 @@ def _invoke(self, sender, call_receive, *requests):
526537
# be on the very first connection (not authorized, not running),
527538
# but may be an issue for people who actually travel?
528539
self._reconnect(new_dc=e.new_dc)
529-
return self._invoke(sender, call_receive, *requests)
540+
return self._invoke(sender, call_receive, update_state, *requests)
530541

531542
except ServerError as e:
532543
# Telegram is having some issues, just retry

0 commit comments

Comments
 (0)