Telegram bot with Rust
by Afanasy Barbarov
Building a Telegram Bot with Rust
After giving Rust another chance, I decided to build something real: a Telegram bot that lets users upload documents and ask questions about them using OpenAI's assistants API.
The requirements were straightforward - accept file uploads, process them through OpenAI's vector search, and stream responses back. What I didn't expect was how well Rust handled the async complexity.
Architecture
┌─────────────┐ ┌──────────────┐ ┌─────────────┐
│ Telegram │───▶│ Rust Bot │───▶│ OpenAI │
│ Webhook │ │ (teloxide) │ │ Assistants │
└─────────────┘ └──────────────┘ └─────────────┘
│
▼
┌──────────────┐
│ PostgreSQL │
│ (users/auth)│
└──────────────┘
│
┌──────────────┐
│ SQLite │
│ (chat state) │
└──────────────┘The bot runs as a single binary with webhook endpoints. When users upload files, they get downloaded locally, uploaded to OpenAI's vector store, then deleted. Chat state persists across restarts using SQLite storage.
User access is gated by promo codes stored in PostgreSQL. Each user gets their own OpenAI assistant instance with attached file storage.
Building with Bazel
Bazel proved excellent for Rust. Cross-compilation to ARM64 and x86_64 with musl linking produces tiny, portable binaries. The final container images are under 20MB.
The build system handles dependency management better than Cargo for this type of deployment. Reproducible builds and hermetic compilation made deployment predictable.
What Worked
The bot has been running for months without issues. Rust's memory safety eliminated entire classes of bugs I'd typically worry about. The async runtime handles concurrent users without performance surprises.
Most importantly, once built, it just works. No memory leaks, no mysterious crashes, no surprise GC pauses. The upfront compiler fights paid off with a service that requires zero maintenance.
Future posts will dive deeper into the Bazel setup and deployment strategies.