Slack Smart Bot: Adding a AWS DynamoDB

Currently, the bot we’ve made in the previous post (first, second) doesn’t use a database. So we are currently cheating by passing channel id and timestamp that we need to for the modal to work as fields in the modal. Instead of doing that, we can use a Database in AWS.

Which Database

AWS has a lot of database offering, that use different tech, and are geared for different purposes. For this bot i’m planing on using NoSQL. For NoSql the database to use would be DynamoDB.

Database Pricing

Before we set up the database, we need to think about pricing. AWS has Pricing Calculator for each of it service that you can see what the pricing will be. Depending on the feature you enable and how many read and write you expecting, the cost can change depending on which feature you turn on. Since we are just making a super simple help bot the only feature we need right now is capacity. There 2 options
Provisioned Capacity. With Provisioned Capacity, you are provisioning resources to meet a specific number of read and write. This is great if you know roughly what the load on the database is going to be. You’ll make a 1 or 3 year commitment and pay monthly.
On-Demand Capacity. You pay for what your use pretty much, with no commitment. For a small project, with the free tier you can pretty much pay 0 until you scale up.

Since this is a small project, and we don’t expect much load. On-Demand is the way to go.

Creating the DyanmoDB

In the DyanmoDB service you want to click on Create new table
Give the table a name, and a Partition Key. The partition key will be the primary key for the database and should unique. In our case this is going to be the timestamp. Also make sure in setting to pick Customize Settings. The only thing we want to customizing is Read/Write capacity settings. Switch these to On-Demand, from Provisioned.

IAM policy and role for access to DyanmoDB

Follow AWS guide on this, there are a lot of little step in IAM, and Lambda to get this to work

Add element to the DB

Currently the script will respond to the user with button to push when they say a keyword that triggers the script. We are going to modify the script to also record the message in to the database. What i did was add a new function add_thread_to_database after we have responded to the user.

def parse_message(event):
    if not is_bot(event) and event["text"] in REPLYWORDS:
        send_text_response(BLOCK_REPLY_V2, event['channel'], event['ts'], event['user'])
        add_thread_to_database(event)
    else:
        print(is_bot(event))

def add_thread_to_database(event):
    dynamodb = boto3.client('dynamodb')
    key_dic = {'ts': {'S': event['ts']},
               'user': {'S': event['user']},
               'channel': {'S': event['channel']},
               'text': {'S': event['text']}}
    dynamodb.put_item(TableName='ts-recorder', Item=key_dic)

After deploying this code in Lambda, you should start getting record in the database. If your not check cloud watch log for error (you may have missed a set when setting up the IAM Role/policies).

Reading from database

Now we have data in the database we want the modal to pull from the database rather than putting ID fields in the modal it self. To do this all we do is call the database with pass in out thread_id and we should get the 4 fields from we put in the database above back. Now we can remove the channel_id, and thread_ts field we added to the module when we didn’t have a database, since we can keep track of these in the database

def get_thread_from_database(thread_id):
    table = boto3.resource('dynamodb').Table('ts-recorder')
    try:
        response = table.get_item(Key={'ts': thread_id})
    except ClientError as e:
        print(e.response['Error']['Message'])
    else:
        return response['Item']

Update a database field

Last thing we want to do is put the field the users enters in the slack modal in to the database as well. First we want to update the parse_responce function. Instead of returning the text to the user, we want to format it in a dictionary that can be given to dyanmodb. The format we want look like this

{<db field name>: {'Action':<DB action (put)>, 'Value': <Value for field>}

With this format dictionary we can pa

def parse_responce(event):
    message = {}
    if event['view']['blocks'][0]['text']['text'] == "Ansible_bug_report":
        for block in event['view']['state']['values']:
            for key in event['view']['state']['values'][block]:
                message[key] = {"Action": "PUT", "Value": event['view']['state']['values'][block][key]['value']}
    if event['view']['blocks'][0]['text']['text'] == "Ansible_new_feature":
        for block in event['view']['state']['values']:
            for key in event['view']['state']['values'][block]:
                message[key] = {"Action": "PUT", "Value": event['view']['state']['values'][block][key]['value']}
    thread_ts = (event['view']['callback_id'])
    db_record = get_thread_from_database(thread_ts)
    user = event['user']['username']
    return message, thread_ts, db_record['channel'], user

def update_thread_to_datebase(thread_ts, message):
    table = boto3.resource('dynamodb').Table('ts-recorder')
    response = table.update_item(
        Key={'ts': thread_ts},
        AttributeUpdates=message,
        ReturnValues="ALL_NEW"
    )
    print('Update Response: ' + response)

Putting it all together

So now we have a slack app that is sending events to an Api Gateway that connect to a Lambda function

The Lambda function will return a message with button to us

Clicking on the button will send a message back to lambda to return a specific modal to the user. As well as write this data to a dynamoDB

Filling this modal out will send the data back to Lambda, which will then store it in the DynamoDB.
We get auto scaling of the DynamoDB and lambda functions for free
We get monitoring in both Lambda and DynamoDB
We can look at our logs in CloudWatch
We don’t have to manage any of these services
And we wrote less than 250 lines of code to get everything works.

Code

https://github.com/carchi8py/help-slack-bot/tree/v3

One thought on “Slack Smart Bot: Adding a AWS DynamoDB

Add yours

  1. Thank you for sharing these articles, they were great for doing what I wanted. I just had a question when I sent the model. It says “We had some connection issues. Try again?” What can I do with this connection failure?

    Like

Leave a comment

Blog at WordPress.com.

Up ↑