S.
Home
AboutProjectsBlogLabGalleryContact
HomeProjectsBlogContact

© 2026 Shohjahon Rajabov. All rights reserved.

Back to blog
Infrastructure
April 18, 2026
2 min read
aiogramRedis

What three Telegram bots taught me about state

The anonymous chat bot worked perfectly on my laptop and fell apart the first time I ran two processes. Here is what I changed.

The first Telegram bot I really cared about was an anonymous chat bot: users join a queue, get matched with a stranger, and the bot relays messages between the two of them. I kept the queue in a Python list and the active pairs in a dict. On my laptop it was flawless.

Then I deployed it, and two things broke almost immediately. Any restart - even a routine one to ship a small feature - wiped every active conversation and emptied the queue. And the first time I wanted a second worker process to keep up, there was no shared truth about who was matched with whom: each process had its own dict, so two people in the 'same' chat could land on different workers and never hear each other.

The fix is the lesson every async service eventually forces on you: state does not belong in the process. I moved the queue and the pair mappings into Redis. After that, any worker can answer 'who is this person talking to?' by reading one key, restarts are invisible to users mid-chat, and scaling out is just running another identical process.

The Instagram downloader bot taught me the other half. Fetching a video is slow and bursty - a link arrives and the download can take several seconds. Do that inline in the handler and the whole event loop stalls for everyone else the moment a few links come in at once. So the handler does almost nothing: it validates the link, drops a job on a Celery queue, and returns. Workers pull the heavy work off the queue at whatever rate they can actually sustain, and per-user rate limiting sits in middleware in front of all of it.

By the time I turned these patterns into the aiogram 3 template I reuse, none of it felt clever anymore. It is the same shape as any backend: keep handlers thin, push state to Redis, push heavy work to a queue. Bots just hide that lesson well, because the naive in-memory version demos perfectly. It only falls over once someone other than you is using it.

Share:Share on Telegram
More posts
Engineering

The caching bug that made me stop trusting TTLs

1 min · February 10, 2026
Engineering

Patterns I use with async SQLAlchemy 2.0

1 min · November 20, 2025