I'm in the process of moving all my stuff from Azure to AWS. One of the things I currently run in Azure is a twitter bot that tweets every hour (it even made the local news a couple of years ago...).
Currently it's beeing triggered by a cron job on a VM. It has worked perfectly fine for 6 years now, but since I'm moving stuff and don't wan't to maintain a VM anymore, I decided to "convert it" to run in a AWS Lambda instead.
The bot is written in Python and has two pip dependencies,
Before the code looked liked this:
from twitter import OAuth, Twitter from datetime import datetime, time import pytz, random TOKEN = "SECRET" TOKEN_KEY = "SECRET" API_KEY = "SECRET" API_SECRET = "SECRET" MY_TZ = pytz.timezone('Europe/Stockholm') now = datetime.now(MY_TZ).time() retries = 0 def get_current_hour(timestamp): if timestamp.hour == 0 or timestamp.hour == 12: return 12 return timestamp.hour % 12 def compose_tweet(timestamp): number_of_rings = get_current_hour(timestamp) # Creates a tweet, e.g. "BONG BONG BONG #03:00 alert_sound = get_bell_sound(retries) tweet = " ".join([alert_sound] * number_of_rings) hashtag = "#%s:%s" %(str(timestamp.hour).zfill(2), str(timestamp.minute).zfill(2)) return "%s %s" %(tweet, hashtag) def send_tweet(tweet): global retries auth = OAuth(TOKEN, TOKEN_KEY, API_KEY, API_SECRET) t = Twitter(auth=auth) try: t.statuses.update(status=tweet) retries = 0 except: retries += 1 if retries <= 7: main() else: raise def get_bell_sound(index): sounds = ('BONG', 'DONG', 'DING', 'BING-BONG', 'RING', 'PING', 'JINGLE', 'DING-DONG') return sounds[index] def main(timestamp = now): send_tweet(compose_tweet(timestamp)) if __name__ == "__main__": main()
To make it "Lambda compatible", I only needed to add the following method
def lambda_handler(event, context): main()
lambda_handler function is called by the lambda runtime. You get access to both the event that triggered the function and also a context. I don't need any of it though.
Here the documentation lacked a little when it comes to how to deploy a python function with external (pip) dependencies. It wasn't that hard to figure out but it took me like 30 minutes that I could have spent on something else, so that's why I'm writing this post :).
Lambda supports uploading a zip file, so let's create one. It needs to contain the pip packages and the entrypoint, in our case the entrypoint is
The easiest way dealing with PIP imo is to have a
requirements.txt file, so let's create one.
Here we have specified which packages and what version to use. I use quite old packages, I don't know if newer versions work and I don't have time to try it out either, so bare with me.
After creating a
requirements.txt, we can install the packages to the current folder like this:
pip install -r requirements.txt -t .
This will create the following folder structure:
Now the only thing left to do is create the zip file.
I added the following files/folders to the zip file:
Then I uploaded it by choosing Upload a .zip file
The UI will now look like this:
Here I've also specified the entrypoint for the function by entering
tweet.lambda_handler in the Handler input field (tweet is the name of the file and lambda_handler is the name of the method).
Now the only thing that's left is to make the function run every hour (08:00, 09:00 and so on).
It's really easy, all we need to do is add a CloudWatch Event Trigger with the following schedule expression:
cron(0 * * * ? *).
That's it, we're now tweeting from the (aws) cloud!
BONG BONG BONG BONG BONG BONG BONG BONG BONG BONG BONG BONG #12:00
— Domkyrkan (@skara_domkyrka) February 9, 2020