Discord Bot in Python Running on Google Cloud Run

6 minute read

Writing a chat bot is maybe something that one does more a junior getting in to programming. It turns out it can still be fun even though I’ve programmed for more than half of my life!

I was still hanging around in various IRC networks until a few years ago, keeping a bouncer (znc) running at an server. While most of these channels died, a group of friends of mine moved on to Discord where we still hang actively. At some point the question came up: “we’re a bounce of developers here; why haven’t we programmed our own bot yet?”. And off we go!

The Bot

The bot itself is for simplicity written in Python with the popular library discord.py. I decided for implementing classing !commands for the bot. Adding a command is not harder then listening for incoming new messages in a channel and doing some string operation. Here’s a simple rot13 A text encoding scheme where you simply rotate the English alphabet 13 letters to the right.
implementation from my bot:

if message.content.startswith("!rot13 "):
    text = message.content[len("!rot13 ") :]
    text_rot = codecs.encode(text, "rot_13")
    await message.channel.send(text_rot)

Now a user can in a server where the bot is added do

User#1> !rot13 rotate this text please
Bot> ebgngr guvf grkg cyrnfr

The actual code looks a bit different in production though, and I created many more commands as well. Check it out at Tardsquad/tardsquad-discord-bot.

Dynamic GitHub repo image with stats

The Infrastructure

As my home has gone server-less, it has to run in the cloud a.k.a some else’s computer. I decided to try out Google Cloud Platform’s managed container platform called Cloud Run. After wrapping up my Poetry project as Docker image (Dockerfile) I needed to figure out how to set up Continuous Delivery Continuous Integration & Continuous Delivery - methodology and development process automation.
to minimize future workload on development of new features that should be deployed.

I tried for a while getting it up to run with two GitHub Actions. RafikFarhad/push-to-gcr-github-action to build a new Docker image and publish it to Google image registry called Container Registry. google-github-actions/deploy-cloudrun to deploy a new service revision of the Cloud Run application using the newly build image. While I got the image build and publish to work and almost the deploy Cloud Run to work, I experience several flaky issues in the solution that I could see break down the line. As it was out of the scope for this simple project, I decided to move away from this solution and take the easy way, of using Google’s Cloud Build Triggers solution to trigger build and deployment of the service. Most of it is codified in my cloudbuild.yaml

A little gotcha with Google Cloud Run is that it’s really designed for web services that respond on a network port. Cloud Run demands that the started service in the docker container must respond to $PORT as an alive-check, otherwise it is considered failed and not kept running. This does not fit well with running a chat bot, as it has not web interface or API that needs to listen to a port. To get this to work, I had to read $PORT from the environment and start a separate thread creating a socket on this port to listen on.

All in all, a fun little project!

Update

After a few months of running this bot I decided that the always-on CPU on Cloud Run is a bit expensive for this use case. Instead I decided to switch over running the dockerized application on Compute Engine instead as the free tier includes one e2-micro VM instance per month.

To get this to work I needed to:

  • Create a VM instance set to automatically run the latest container image published to Cloud Registry.
  • Update the Cloud Build pipeline to redeploy the latest container image and restart the VM by creating a new deploy step in the cloudbuild.yml config.

Leave a comment

Your email address will not be published. Required fields are marked *

Loading...