Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
FROM python:3.8.12-slim-buster

# YOUR COMMANDS HERE
# ....
# ....
WORKDIR /TelegramAI
COPY . .
RUN pip install -r requirements.txt

CMD ["python3", "app.py"]
38 changes: 38 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# AWS Ex1 - Provision the TelegramAI app in AWS

## Background

Your goal is to provision the TelegramAI chat app as a scalable, micro-services architecture in AWS.

Here is a high level diagram of the architecture:

![](botaws2.png)

## Scaling the app

When end-users send a message via Telegram app (1-black), the messages are served by the Bot service (run as a Docker container in the Telegram Bot EC2 instance).
The Bot service **doesn't** download the video from YouTube itself, otherwise, all it does is sending a "job" to an SQS queue (2-black), and return the end-user a message like "your video is being downloaded...".
So, the Bot service is a very lightweight app that can serve hundreds requests per seconds.
In the other side, there are Worker service (run as a Docker container in the Worker EC2 instance) **consumes** jobs from the SQS queue (3-black) and does the hard work - to download the video from YouTube and upload it to S3 (4-black). When the Worker done with current job, it asks the SQS queue if it has another job for him. As long as there are jobs pending in the queue, a free Worker will consume and perform the job. In such way the Bot service pushes jobs to the SQS queue, making it "full", while the Worker service consumes jobs from the queue, making it "empty".

But what if the rate in which the Bot service is pushing jobs to the queue is much higher than the rate the Worker completing jobs? In such case the queue will overflow...
To solve that, we will create multiple workers that together consume jobs from the queue. How many workers? we will deploy a dynamic model **that auto-scale the number of workers** depending on the number of messages in the queue.
When there are a lot of jobs in the queue, the autoscaler will provision many workers.
When there are only a few jobs in the queue, the autoscaler will provision fewer workers.
The Workers are part of an AutoScaling group, which is scaled in and out by a custom metric that the Metric Sender service (run as a Docker container as well, on the same VM as the Bot service) writes to CloudWatch every 1 minute (1-blue). CloudWatch will trigger an autoscale event (2-blue) when needed, which results in provisioning of another Worker instance, or terminate a redundant Worker instance (3-blue).

The metric sent to CloudWatch can be called `BacklogPerInstance`, as it represents the number of jobs in the queue (jobs that was not consumed yet) per Worker instance.
For example, assuming you have 5 workers up and running, and 100 messages in the queue, thus `BacklogPerInstance` equals 20, since each Worker instance has to consume ~20 messages to get the queue empty. For more information, read [here](https://docs.aws.amazon.com/autoscaling/ec2/userguide/as-using-sqs-queue.html).

### The TelegramAI repo structure

The repository structure is divided into services - each service under its own directory, while all services are sharing common files (`config.json` and `utils.py`) under the root directory of the repo.

1. `bot/app.py` - The Telegram bot code, similar to what you've implemented in the previous exercise. But this time, the bot doesn't download the videos itself, but sends a "job" to an SQS queue.
2. `worker/app.py` - The Worker service continuously reads messages from the SQS queue and process them, which means download the video from YouTube and store it in a dedicated S3 bucket.
3. `metric-sender/app.py` - The Metric Sender service calculates the `backlog_per_instance` metric and send it to CloudWatch.

Each service has its own `Dockerfile` under the service's directory.
## Diagram of the lambada architecture:

![](botaws3.png)
18 changes: 14 additions & 4 deletions app.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,10 @@ def download_user_photo(self, quality=0):

file_info = self.bot.get_file(self.current_msg.photo[quality].file_id)
data = self.bot.download_file(file_info.file_path)
with open(file_info.file_path,'wb') as p:
p.write(data)


# TODO save `data` as a photo in `file_info.file_path` path

def handle_message(self, message):
"""Bot Main message handler"""
Expand All @@ -61,14 +63,22 @@ def handle_message(self, message):


class YoutubeBot(Bot):
pass
def handle_message(self, message):
if self.is_current_msg_photo():
self.download_user_photo(quality=3)
return

video = search_download_youtube_video(message.text)
self.send_text(video[0].get("url"))


if __name__ == '__main__':
with open('.telegramToken') as f:
_token = f.read()

<<<<<<< HEAD
my_bot = YoutubeBot(_token)
=======
my_bot = Bot(_token)
>>>>>>> upstream/main
my_bot.start()


Binary file added botaws2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added botaws3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.