Building My Serverless Discord Bot
This blog post is an overview of the process involved in creating a Discord bot designed to automate weather forecast announcements over the span of 10 days. My objective was to develop a solution that delivers weather updates for cities.
As my friends and I gathered regularly on Discord, a peculiar routine emerged. Among us was a friend named Ned (not his actual name), who took it upon himself to post the weather forecast for Toronto every morning on the server. In response, we'd all respond to him with a "GM @Ned".
Over time, the Discord server expanded and new members from different cities joined. Ned started posting forecasts for multiple cities to accommodate everyone. Witnessing his daily dedication, it struck me that there had to be a simpler way to streamline this process and free up Ned's time.
And so, the idea of building a Discord bot to automate weather forecast announcements took root. I saw an opportunity to not only ease Ned's load but also provide a valuable service to the server community, ensuring they stayed informed about the weather in their respective cities.
The first step was to define the essential requirements the Discord bot had to fulfill. To ensure a structured approach, requirements are categorized into functional and non-functional aspects, outlining the key features and characteristics I aimed to achieve.
Simple and informative forecasts
The bot that would deliver weather information in a straightforward and informative manner. Just clear and concise updates everyone could understand.
Moderator-managed city list
Server moderators should be able to easily manage the list of cities for which forecasts would be generated.
Send forecasts for a list of cities
The bot will provide weather forecasts for a handpicked selection of cities. The server members to have easy access to weather updates.
Automatic reaction to messages tagging Ned
It would be a fun and engaging feature to have it automatically respond to messages tagging the user "Ned."
- Zero cost operations
- User-friendly interface
- Secure to avoid malicious use of the bot
- Scalable that could handle increased user engagement
By laying out these well-defined requirements, I had a good foundation for the subsequent stages of development. With these goals in mind, I can start designing the Discord bot.
The next step was to create an weather forecast infographic generator. The purpose of this system is to fetch weather data for a given location and present it in a visually appealing and easily understandable format.
For the weather forecast infographic generator, I will be using:
It enables access to weather conditions, forecasts, historical data, and more. The decision to use this API was driven its free tier suitable for many small-scale projects.
Vercel's OG Image Generation
It allows us to dynamically create images directly from JSX components. This feature enables us to generate custom weather forecast infographics on-the-fly based on the data fetched from the OpenWeather API.
The requirements for the weather forecast infographic were:
- Display current weather conditions
- Display weather conditions every 3 hours for the next 9 hours
- Support celsius and fahrenheit units
- Display icon for the weather conditions
- Requests to generate forecast images must include a signed tokens to prevent malicious use
This was the simple design for the generated forecast of a city:
By leveraging Vercel's edge functions, I can ensure that the infographics are generated efficiently and served quickly to the end-users. The sequence diagram below outlines what happens when an user makes a request to the Discord bot for a weather forecast.
All weather forecast requests from Discord are responded with ephermeral responses to let the user know their request is processing, they will see "Ned is thinking..." with a loading animation.
At the same time, the request is sent to a queue to throttle request processing times as a workaround for Discord's rate limiting. When the message in the queue is processed, it will fetch the weather data and generate a weather forecast inforgraphic image and send it to Discord's API to update the message from "Ned is thinking..." to the generated image.
I designed and created a user-friendly website dedicated to helping the moderators manage the list of locations for which weather forecasts would be routinely sent. It was essential to ensure that only authorized moderators could access the website, preventing any potential misuse by unintended users. To achieve this, I implemented Discord authentication, which checked for the presence of a moderator role before granting access.
To cater to the diverse target audience, the website was designed to be responsive and deliver a clean interface on both desktop and mobile platforms, ensuring a clean user experience regardless of the device used.
The website boasted two pages, each serving a specific purpose:
The browse page provided an intuitive interface for moderators to search and explore various locations they wished to add to the weather forecast service. This allowed us to continuously expand the coverage and ensure that server members had access to forecasts for their preferred locations.
The saved locations page served as a central hub for tracking all the locations that moderators had added to the system. This feature enabled us to keep an organized record of the cities and regions we were providing forecasts for, making it easier to manage and update the list as needed.
Here are boring behind-the-scenes details on performance improvements made for this tool:
Server-Sided Rendering for React Components
To optimize performance and ensure faster loading times, I opted for server-sided rendering (SSR) for the React components. This approach allowed us to pre-render the components on the server before sending them to the client, resulting in a snappy and responsive user interface.
Automated CI/CD using Vercel and Github Actions
With a focus on continuous integration and continuous deployment (CI/CD), I harnessed the power of Vercel and GitHub Actions to automate the deployment process. This streamlined workflow ensured that any updates or changes to the website were promptly and automatically deployed, saving us time and effort.
Caching for Integrated APIs
To optimize data retrieval and minimize the strain on integrated APIs, I implemented caching mechanisms. Specifically, I applied caching to city searching, allowing us to store recent search results locally. This way, we reduced redundant API calls and improved overall response times for the users.
Scope-Based Rate Limiting on APIs
To maintain a fair and reliable service, I employed scope-based rate limiting on the APIs we integrated. This prevented excessive use of the APIs and helped us stay within usage limits, ensuring we didn't inadvertently overwhelm the services we relied upon.
Automating the daily weather forecasts to be sent promptly at 7 am EST was a easy. I created a CRON job using Inngest to handle the scheduled tasks.
To ensure secure access to the required data, I implemented authenticated requests using signed tokens. This added an extra layer of protection, ensuring that only authorized users and processes could trigger the forecast generation. With the system in place, the server community could wake up to the latest weather updates every morning.
I stumbled upon a small roadblock. It turned out that creating real-time reactions to messages was not natively supported within this framework. Undeterred, I refused to let this limitation halt the progress.
To overcome this obstacle and add the desired feature, I decided to create another Discord bot service, taking a more traditional approach by running it on my own dedicated server. This new bot would handle the real-time reactions, complementing the serverless architecture.
To ensure seamless integration and efficient deployment, a Github Actions workflow was setup to build Docker images were uploaded to Docker Hub which is a image registry.
I set up a webhook that listened for new commits merged into my master branch and that would trigger script to deploy the Docker image onto my personal Linux server.
Looking back at the process for creating this weather forecast automation Discord bot, I can't help but feel a sense of satisfaction because the project went well.
Defining well-structured requirements was the key to a successful implementation. Categorizing functional and non-functional aspects helped us maintain clarity and focus throughout the development process. The bot would fulfill its purpose effectively by adhering to the requirements.
One area where I can enhance the user experience is by introducing support for different time zones. Currently, the bot delivers weather updates at a fixed time, 7 am EST, every day. While this is suitable for some users, it may not be ideal for others residing in different parts of the world.
Seeing Discord server members engage with the bot and appreciate its value was truly rewarding.