telethon-floodgate
Flood-wait handling for Telethon user accounts: a proactive rate-limit gate, a reactive circuit breaker, and flood-wait sleep/retry helpers — three layers that keep a working account out of Telegram's multi-hour FLOOD_WAIT bans.
Telegram does not publish rate limits. This library is the production flood
stack of a multi-account Telegram content collector, calibrated against real
incidents: a fresh session firing 160+ auth.resolveUsername calls in seconds
escalated into 15–18 hour bans, and repeated getDialogs sweeps ran a account
into a 14.8-hour ban. The defaults are deliberately conservative and every
bucket is configurable.
Install
pip install telethon-floodgate
Requires Python 3.11+, Telethon 1.x, pydantic 2.x and pybreaker.
The three layers
1. Proactive rate-limit gate — before the call
from telethon_floodgate import TelegramRateLimitGate, TelegramRateLimitedError
gate = TelegramRateLimitGate() # create once, next to your client pool
def before_telegram_call(phone: str, operation: str) -> None:
category = gate.category_for(operation) # "send", "history", "dialogs", ...
retry_after = gate.try_acquire(phone, category)
if retry_after > 0:
raise TelegramRateLimitedError(phone, category, retry_after)
Buckets are independent sliding windows keyed by (phone, category):
dialogs (1/min — the #1330 incident), dialog_sweep, history,
admin_action, send (30/min), channel_lifecycle (3 per 5 min), plus a
permissive default. Override any of them:
from telethon_floodgate import RateLimitSpec, TelegramRateLimitGate
gate = TelegramRateLimitGate(
category_limits={"send": RateLimitSpec(max_calls=10, window_sec=60.0)}
)
resolve and reaction are intentionally no-op categories: in the origin
project those paths have dedicated limiters (see ResolveRateLimiter, also
shipped here).
Per-peer send limits
Telegram throttles sending per peer, not just per account: roughly one
message per second to the same private chat and about twenty per minute into
the same group or channel. Pass a peer key to try_acquire and the gate
checks a second, independent (phone, category, peer) bucket before the
category one:
from telethon_floodgate import peer_key
retry_after = gate.try_acquire(phone, "send", peer=peer_key(entity))
if retry_after > 0:
raise TelegramPeerRateLimitedError(phone, peer_key(entity), retry_after)
- A per-peer refusal does not consume the account-wide category slot, so a burst aimed at one peer cannot burn the account budget.
peer_key()derives"user:123"/"channel:-100123"/"chat:-456"/"username:durov"/"id:123"from ints, strings, Telethon TL peers, input peers and full entities — purely local attribute access, never a network round-trip.- Only
send:user,send:channelandsend:chatare configured by default; unknown kinds pass through unthrottled. Override or disable viapeer_limits(a"send:user"entry with a permissive spec effectively turns it off) and cap memory withpeer_max_buckets(LRU, default 4096).
gate = TelegramRateLimitGate(
peer_limits={"send:user": RateLimitSpec(max_calls=1, window_sec=5.0)},
peer_max_buckets=4096,
)
TelegramPeerRateLimitedError subclasses TelegramRateLimitedError, so one
"operation unavailable, move on" handler covers every layer.
2. Reactive circuit breaker — when Telegram answers anyway
from telethon_floodgate import FloodCircuitBreaker
breaker = FloodCircuitBreaker(threshold=3, cooldown_seconds=300)
breaker.check(operation, phone) # raises TelegramOperationSuspendedError
# while the pair is suspended
try:
await client.some_call()
breaker.record_success(operation, phone)
except telethon.errors.FloodWaitError:
breaker.record_flood(operation, phone)
After threshold flood waits on the same (operation, phone) the pair is
suspended for cooldown_seconds, then exactly one half-open trial call is
allowed. TelegramOperationSuspendedError subclasses
TelegramRateLimitedError, so a single "operation unavailable, move on"
handler covers both layers.
3. Flood-wait helpers — classify, sleep, retry, report
from telethon_floodgate import (
HandledFloodWaitError, FloodWaitInfo,
handle_flood_wait, run_with_flood_wait, run_with_flood_wait_retry,
is_transient_flood_wait_seconds, is_blocking_flood_wait_until,
)
# wraps one awaitable: FloodWaitError -> HandledFloodWaitError (+ pool report)
await run_with_flood_wait(client.get_dialogs(), operation="warm", phone=phone, pool=pool)
# retries transient waits (<=60s) under a total budget (120s default)
await run_with_flood_wait_retry(factory, operation="fetch", phone=phone, pool=pool)
handle_flood_wait reports the wait back to the pool via
await pool.report_flood(phone, seconds) so account rotation can skip the
flooded account — persist that to your own storage; the library is
storage-agnostic.
Design notes
- Everything runs on one event loop; the limiter state is plain in-memory deques, no locks, no DB.
try_acquirenever sleeps and never raises — it returns seconds to defer, so callers decide whether to reschedule, skip or await.- Atomic multi-slot reservations (
try_acquire(..., slots=n)) are supported for compound operations.
License
MIT — see LICENSE. Unofficial third-party library; not affiliated with the Telethon project.
Metadata
Release files for telethon-floodgate 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| telethon_floodgate-0.1.0.tar.gz | 27.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| telethon_floodgate-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 48.3 kB
Release files / telethon_floodgate-0.1.0.tar.gz
| Download URL | telethon_floodgate-0.1.0.tar.gz |
|---|---|
| Size | 27.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e6fbc92019a2bb2b58bdeea5f6cf66bd3da5a15e88383f9b07702a125d363089
|
|
BLAKE2b-256 checksum How to use checksums |
18bcabb6114a702ecddd1ce67132d6f4c9da506423c5056d4fcbc1049965001c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.15
|
Release files / telethon_floodgate-0.1.0-py3-none-any.whl
| Download URL | telethon_floodgate-0.1.0-py3-none-any.whl |
|---|---|
| Size | 20.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
31449e6cf288196b63159029a40a01c5408c3949d3e04cf3a68be191cec28523
|
|
BLAKE2b-256 checksum How to use checksums |
9c2919d55bd9d0d7e7bf5369cf5a72bd2cb5d6a751d0a586b0960f16e6646fce
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.15
|