Skip to content

Make stopping the client safe#664

Merged
alexander-akhmetov merged 1 commit into
mainfrom
fix-client-shutdown
Jul 24, 2026
Merged

Make stopping the client safe#664
alexander-akhmetov merged 1 commit into
mainfrom
fix-client-shutdown

Conversation

@alexander-akhmetov

@alexander-akhmetov alexander-akhmetov commented Jul 24, 2026

Copy link
Copy Markdown
Owner

Fixes two ways stop() can break the client.

_close() waits for the CLOSED authorization state with no timeout and raise_exc=True. When tdlib does not answer, stop() blocks forever. When it answers with an error, the exception escapes before self._stopped.set(), so idle() never returns, the listener thread keeps running and the tdlib client is never destroyed.

TDJson.stop() sets td_json_client to None, but send, receive and td_execute kept passing it to tdlib. ctypes turns None into NULL and tdlib dereferences it, so any call after stop() killed the process instead of raising. They now raise ClientDestroyedError, and the listener thread breaks out of its loop on it instead of spinning.

Copilot AI review requested due to automatic review settings July 24, 2026 22:12
@alexander-akhmetov
alexander-akhmetov merged commit 8ef166e into main Jul 24, 2026
11 checks passed

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR hardens shutdown behavior for the Telegram client/TDLib wrapper by preventing indefinite blocking during stop() and by guarding TDLib calls after the underlying TDLib client handle has been destroyed.

Changes:

  • Add a close_timeout parameter to Telegram.stop() and implement bounded waiting in _close() while polling authorization state.
  • Introduce ClientDestroyedError and ensure TDJson.send/receive/td_execute raise instead of passing a NULL handle into the C library.
  • Extend tests and changelog entries to cover safe shutdown scenarios and listener behavior when the client is destroyed.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
tests/test_telegram_methods.py Adds regression tests ensuring stop() and _close() finish under timeouts/errors and listener exits on destroyed client.
tests/test_tdjson.py Adds tests that TDJson methods raise after stop and do not call underlying C functions.
telegram/utils.py Updates AsyncResult.wait() timeout type to float to support sub-second timeouts.
telegram/tdjson.py Adds ClientDestroyedError, tracks the client handle as nullable, and guards C calls via _get_client().
telegram/client.py Adds bounded shutdown (close_timeout), improves robustness of stop(), and prevents listener spinning on destroyed-client usage.
docs/source/changelog.rst Documents the new safe-stop behavior and the post-stop exception change.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread telegram/client.py
Comment on lines 205 to 208
result = self.get_authorization_state()
self.authorization_state = self._wait_authorization_result(result)
self.authorization_state = self._wait_authorization_result(result, timeout=time_left)
logger.info("Authorization state: %s", self.authorization_state)
time.sleep(0.5)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants