Long polling¶
With long polling, the bot asks the server “anything new?” and the server answers as soon as something arrives, or after up to 50 seconds with an empty list. It works from any computer, even behind a home router: you don’t need a public address. It is the default.
bot.run() # blocks until Ctrl+C or SIGTERM
Inside your own asyncio program:
async def main():
task = asyncio.create_task(bot.start_polling())
...
await bot.stop() # finishes running handlers, then returns
await task
Options¶
Option |
Default |
Meaning |
|---|---|---|
|
|
how long each request may wait on the server, 0 to 50 seconds |
|
|
how many updates one request may bring, 1 to 100 |
|
|
if a webhook is set, remove it and poll. Without this, the bot refuses to start ( |
|
|
throw away the updates that queued while the bot was off, without handling them |
|
|
|
How updates are confirmed¶
The server keeps every update until the bot confirms it. A bot confirms by sending, in its
next request, the number of the last update it is done with, plus one (the offset). The
server then deletes everything below that number, for good.
The library never confirms an update before it is safe:
with
SQLiteStorage, an update is safe once it is written to the database. The bot confirms it at the next request, even if its handler has not run yet. If the process crashes, the update is still in the database and runs at the next start;with
MemoryStorage(the default), an update is safe only once its handler has finished. The bot waits for the whole batch to be handled before it asks for more. If the process crashes, the server still has the updates and sends them again.
Either way, an update can be handled twice if the process dies at the wrong moment (after
the handler ran, before the confirmation reached the server). The library removes duplicates
it can see, by updateId. For actions that must never happen twice (a payment, an order),
make them idempotent in your own code too: check whether you already did it.
An update that fails (its handler raised and no error handler took the error) is confirmed too, so it does not block the others, and it is kept in the failed list. See Storage.
Only one poller per bot¶
The server allows one long poll per bot at a time. A second request ends the first one at once with an empty answer, so two copies of the same bot that poll will take turns and get nothing done.
With
SQLiteStorage, the library takes a lock on the database (an operating system lock, freed even if the process dies). A second process with the same file fails at start withPollingConflictError, which tells you the process ID of the first one.With
MemoryStoragethe library cannot see the other process. If several polls in a row come back empty right away, it logs a warning: “another process is probably polling this bot”.
To handle more work, raise concurrency, or switch to a webhook.
When things go wrong¶
What happens |
What the bot does |
|---|---|
the network fails, the server answers |
waits a little (longer each time) and tries again, without end |
|
waits as long as the server says |
the owner paused the bot ( |
logs it once, checks again every 30 seconds, and goes on when the bot is resumed |
the token is wrong or revoked ( |
stops with |
a webhook was set meanwhile ( |
stops with |
At start-up the bot also waits for the server if it is down, instead of failing.
Stopping¶
Ctrl+C, SIGTERM (what systemd, Docker and Kubernetes send) and, on Windows,
Ctrl+Break all stop the bot cleanly:
it stops asking for updates, at once: a long poll in progress is dropped, and what it brought was not confirmed, so the server sends it again next time;
it waits for the handlers that are running, up to
shutdown_timeout(30 seconds);handlers still running after that are cancelled. Their updates stay in the queue (with
SQLiteStorage) or on the server (withMemoryStorage), and run again at the next start.
To stop from your own code, call bot.request_stop(): it returns at once, from a handler or
from another thread, and run() then stops as above. await bot.stop() does the same and
waits until the bot has stopped (called from inside a handler, it only asks, so that it does
not wait for itself).
Updates that wait for too long¶
The server keeps updates for 72 hours. A bot that is off for longer loses the oldest ones. When
the bot comes back after a long pause and the old messages no longer matter, start it with
skip_pending=True.