$ cd ..

How I deploy my ~4,000 MAU Python Telegram bot

đź“… 2022-09-24

⌛ 548 days ago

đź•‘

Introduction

SuperSeriousBot logo

I often get asked about what the “best” way to deploy a Python Telegram bot is. I’ve tried a lot of different ways, and I’ve settled on a workflow that I’m quite happy with for @SuperSeriousBot. It’s probably not ideal and I’d like to change a few things, but it’s a process that has evolved over the last ~4 years.

Committing

In general I like to follow KISS for my projects. The actual code of @SuperSeriousBot is fairly straightforward. In a nutshell:

The code is stored on GitHub. For releases, I follow the Angular commit message convention. Using this, I’m able to largely automate the process of version management by using semantic-release.

Building

Being on GitHub, I make heavy use of GitHub actions. I have a workflow that runs on every push to the master branch. This workflow does the following:

I’ve tried to trim down the Docker image size but it still sits at around ~400MB. This part’s still a work in progress. Lately, I’ve also been looking into Nuitka for static binaries. No luck on that front so far. All builds are cached based on poetry.lock so we never rebuild layers. It matters a lot when you’re building for multiple architectures.

As of right now, there’s no tests. It’s up for discussion if I’ll ever add any. To me, a good code review process and robust logging is sufficient for a side project.

Here’s the .releaserc I use to automate the version management and changelog generation:

{
  "branches": ["master"],
  "plugins": [
    "@semantic-release/commit-analyzer",
    "@semantic-release/release-notes-generator",
    "@semantic-release/changelog",
    "@semantic-release/git",
    "@semantic-release/github"
  ]
}

Deploying

I use watchtower to automatically update my Docker containers. I have a docker-compose.yml file that looks like this:

version: "3"
services:
  ssgbot: ...

  redis: ...

  watchtower:
    image: containrrr/watchtower
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    command: --interval 30

It’s not a zero downtime deployment, so I usually like to do it in the late AMs. Along with the bot itself, I use a mix of Redis and SQLite for caching and persistence. In production, I run @SuperSeriousBot in webhook mode. I front the bot with nginx for which I use systemd.

Conclusion

I find this setup to be quite robust and easy to maintain. If you have any suggestions, feel free to reach out to me on Telegram at @obviyus.

Wishlist