Jarvis: Slack notification framework

Do you run crons regularly and are worried about the progress of your cron? Or are simply curious if they’ll run perfectly or not? Or maybe you want to store logs in your server and send some part of those logs or the entire log file to yourself, in case of an exception, and want to avoid seeing a long list of logs in Elastic search / Cloudwatch. Or are you looking for a convenient way to send stats (in form of jpeg or CSV) of your server to your team on slack? Either way, Jarvis is the perfect tool for you!

Be it sending notifications on your dedicated slack channel and tagging the entire channel / yourself or just sending a message with or without any attachment, Jarvis does the deed.

It is a dedicated tool that can be integrated with your server/cron that sends a slack notification to a given channel name according to your requirement. All you need to do is just add Jarvis to your channel, and call a simple lambda code with all the required parameters and you will receive your notifications.

How Jarvis helped to smoothen things out at slice!

We, as a data-team run several crons for migration and data updation in databases. So, quite naturally, we wanted to be kept informed if a cron execution was completed or there was any kind of exception in any of the crons. Hence, Jarvis was created for a smooth transmission of notifications.
In case of an exception, we wanted to inform everyone in the team immediately, so that the team could act upon it at their earliest. 

Finally, the ultimate requirement that motivated us to create Jarvis was also that we wanted to send an attachment in our notification like CSV or Log file.

So, in short, the main aim for the creation of Jarvis was –


“To create a centralized tool that can be used by different services and codebases to send a notification to slack for different actions with or without an attachment”

Architecture

The basic architecture of Jarvis is pretty simple. Here’s a run-through:

The whole codebase of Jarvis runs in an AWS lambda code. If any server/cron wants to send a notification, then the flow is as follows.

  1. If the user wants to send a notification without any attachment
    1. User has to call the lambda function with the required function and then a slack notification gets sent to the given channel name, provided that the Jarvis app is added to your slack channel.
  2. If the user wants to send a notification with any attachment
    1. User needs to upload the required document from their machine to a predefined S3 bucket (in preferred format i.e., key should be /service_name/ file
    2. Next, they need to call the lambda function with the required function and a slack notification will be sent to the given channel name, provided that the Jarvis app is added to your slack channel.

How to add Jarvis to your channel:

  1. Go to your channel.
  2. Click on add app

3. Select Jarvis

Without adding the Jarvis app to your channel, you cannot send a notification to that channel.

How to invoke lambda function with custom payload

Lambda can be invoked with custom payload with or without an attachment. Here’s how:

  • Without attachment

    To send a notification, you need to invoke the lambda with the given payload
{
    "heading": "Heading",
    "message": "Message",
    "slack_channel": "slice-lambda-notifications"
}

// Here heading is optional while message and slack_channel are compulsory parameters. 
slack_channel is the channel name where you want to send the notification.

  • With attachment

To send an attachment (CSV, jpeg) using Jarvis we need to follow the given steps:

  1. Your code or product should upload the attachment in S3, in bucket slack-notification-framework-attachments before triggering the notification.
  2. As a good practice please upload your file at
    s3://slack-notification-framework-attachments/<channel name>/<attachment file>.<file format>
  3. Invoke the lambda using the following payload
{
    "heading": "Heading",
    "message": "Message",
    "slack_channel": "slice-lambda-notifications",
    "attachment": {
        "bucket": "slack-notification-framework-attachments",
        "key": "testing/test_file.csv"
    }
}
// Here heading is optional while attachment, message, and slack_channel are compulsory.
slack_channel is the channel name where you want to send the notification

How to involve the whole channel/user in the slack notification

If you want to send a notification in which the whole channel needs to be tagged, just send a message with appended <!channel> to the message key in the payload

Example:

If your message key is:  “Failure in deleting file”

And you want to tag the whole channel, send the message key as: <!channel>  Failure in deleting file

If you want to send a notification in which a particular user is tagged, just send a message with appended <@UserId> to the message key in the payload

Example:

If your message key is:  “Failure in deleting file”

And you want to tag the person,  send the message key as: <@UNKDY50FH>  Failure in deleting file

How to invoke lambda from code

NodeJS

var AWS = require('aws-sdk');

// you shouldn't hardcode your keys in production! See http://docs.aws.amazon.com/AWSJavaScriptSDK/guide/node-configuring.html
AWS.config.update({accessKeyId: 'akid', secretAccessKey: 'secret'});

var lambda = new AWS.Lambda();
var params = {
  FunctionName: 'slice-slack-notifier', /* required */
  Payload: JSON.stringify({
      {
                "heading": "Heading",
                "message": "Message",
                "slack_channel": "slice-lambda-notifications",
                "attachment": {
                    "bucket": "slack-notification-framework-attachments",
                    "key": "testing/test_file.csv"
                }
}
    }) /*Payload as defined above*/
};
lambda.invoke(params, function(err, data) {
  if (err) console.log(err, err.stack); // an error occurred
  else     console.log(data);           // successful response});


Python

import boto3
boto3_session = boto3.Session(region_name="ap-south-1")
lambda_client = boto3_session.client("lambda")
lambda_client.invoke(
    FunctionName='slice-slack-notifier',
    InvocationType='RequestResponse',
    Payload=json.dumps(
        {
            {
            "heading": "Heading",
            "message": "Message",
            "slack_channel": "slice-lambda-notifications",
            "attachment": {
                "bucket": "slack-notification-framework-attachments",
                "key": "testing/test_file.csv"
            }
            }
        }
    ).encode("utf-8")
)



Error in payload / Notification message:

In case, an error occurs in sending the notification because of the payload or message format, a notification with the required error message will be sent to slack channel  #jarvis-error-notifications

That was all about Jarvis and how it has simplified transmission of notifications into our slack channels with or without an attachment. Here at slice, we are constantly working towards creating new tools, every day, to streamline our workflow. So, stay tuned for more!