Scheduling Slack Messages Using AWS Lambda: A Serverless Approach

Serverless computing has transformed how we build and deploy applications in the cloud. With serverless, you can focus solely on your application code without worrying about provisioning or managing servers. AWS Lambda is the most popular serverless compute service, allowing you to run code in response to events or on a schedule, while only paying for the compute time you actually consume.

In this post, we‘ll walk through how to use AWS Lambda to send scheduled messages to a Slack channel. This is a great way to automate routine communications, share key metrics with your team on a regular basis, or just add some fun to your workday. While we‘ll be using Slack and the Hacker News API in this example, the same approach can be adapted for other APIs and chat services.

Application Overview

Here‘s a high-level look at the flow of our application:

[Simple architecture diagram showing CloudWatch Event triggering Lambda function to retrieve data from API and post to Slack]
  1. We configure a CloudWatch Events rule to trigger our Lambda function on a specified schedule (e.g. every weekday at 9am).

  2. At the scheduled time, CloudWatch Events invokes our Lambda function.

  3. The Lambda function makes a request to an external API (in this case the Hacker News API) to retrieve data.

  4. The Lambda function processes the API response and formats a message to send to Slack.

  5. The formatted message is posted to a Slack channel using the Incoming Webhook URL.

This serverless architecture means we don‘t need to run any dedicated servers, and our Lambda function will only run (and incur charges) when triggered by the CloudWatch Events schedule. Let‘s walk through the steps to set this up.

Setting Up the AWS Resources

1. Create an IAM Role for the Lambda Function

First, we need to create an IAM role that our Lambda function will assume. This role defines the permissions that the Lambda function will have.

In the IAM console, create a new role and select AWS Lambda as the trusted entity. Then attach the following permissions policies:

  • AWSLambdaBasicExecutionRole: Allows the Lambda function to write logs to CloudWatch Logs.
  • AmazonAPIGatewayInvokeFullAccess: Allows the Lambda function to invoke API Gateway endpoints (not used in this example but good to include for extensibility).

2. Create the Lambda Function

In the Lambda console, create a new function and choose the "Author from scratch" option. Give your function a name, select Node.js as the runtime, and choose the IAM role you created in the previous step.

For the function code, we‘ll come back and add that in a later section once we‘ve written it. For now, just use the default sample code.

Under "Environment variables", add a new variable named SLACK_WEBHOOK_URL and set it to the URL for your Slack Incoming Webhook (we‘ll set this up in a later step).

3. Configure the CloudWatch Events Rule

In the CloudWatch console, navigate to the "Rules" section under "Events". Create a new rule.

Under "Event Source", choose "Schedule" and define your desired schedule using cron or rate expressions. For example, to trigger the Lambda function every weekday at 9am UTC, you would use the following cron expression:

cron(0 9 ? * MON-FRI *)  

Under "Targets", add your Lambda function.

Give your rule a name and description, then click "Create rule".

Writing the Lambda Function Code

Now let‘s dive into the Node.js code for our Lambda function. We‘ll break it into a few modules for clarity and testability.

index.js

This is the entry point for our Lambda function. It handles invoking the other modules and responding to the triggering event.

const fetchTopStories = require(‘./hackernews‘);
const postToSlack = require(‘./slack‘);

exports.handler = async (event) => { try { const topStories = await fetchTopStories(); await postToSlack(topStories); console.log(‘Successfully posted top stories to Slack‘); return { statusCode: 200, body: ‘Success‘ }; } catch (err) { console.error(err); return { statusCode: 500, body: ‘Error occurred‘ }; } };

hackernews.js

This module handles fetching data from the Hacker News API. It retrieves the top 5 stories and returns an array of story objects.

const https = require(‘https‘);

const getJson = (url) => { return new Promise((resolve, reject) => { https.get(url, res => { let data = ‘‘; res.on(‘data‘, chunk => { data += chunk; }); res.on(‘end‘, () => { resolve(JSON.parse(data)); }); }).on(‘error‘, err => { reject(err); }); }); };

module.exports = async () => { const topStoriesUrl = ‘https://hacker-news.firebaseio.com/v0/topstories.json‘; const storyIds = await getJson(topStoriesUrl);

const storyRequests = storyIds.slice(0, 5).map(id => getJson(https://hacker-news.firebaseio.com/v0/item/${id}.json)
);

const stories = await Promise.all(storyRequests);

return stories.map(story => ({ title: story.title, url: story.url, score: story.score, author: story.by })); };

slack.js

This module formats the message and posts it to Slack using the Incoming Webhook.

const https = require(‘https‘);

module.exports = (stories) => { const slackMessage = { text: ‘Top Hacker News Stories‘, attachments: stories.map(story => ({ title: story.title, title_link: story.url, text: ${story.score} points by ${story.author}
})) };

const options = { method: ‘POST‘, hostname: ‘hooks.slack.com‘, path: process.env.SLACK_WEBHOOK_PATH };

return new Promise((resolve, reject) => { const req = https.request(options, (res) => { let data = ‘‘; res.on(‘data‘, (chunk) => { data += chunk; }); res.on(‘end‘, () => { resolve(); }); }); req.on(‘error‘, (error) => { reject(error); }); req.write(JSON.stringify(slackMessage)); req.end(); }); };

Setting Up Slack Incoming Webhook

To post messages to Slack, we need to set up an Incoming Webhook. Here‘s how:

  1. Navigate to https://api.slack.com/apps and click "Create New App".

  2. Give your app a name and select your Slack workspace.

  3. Under "Add features and functionality", click "Incoming Webhooks".

  4. Toggle on "Activate Incoming Webhooks".

  5. Scroll down to "Webhook URLs for Your Workspace" and click "Add New Webhook to Workspace".

  6. Choose the channel where messages will be posted and click "Allow".

  7. Copy the Webhook URL. This is what you‘ll need to set as the SLACK_WEBHOOK_URL environment variable in your Lambda function.

Deploying and Testing

With our code written and Slack webhook set up, we‘re ready to deploy. Zip up your Node.js files and upload the zip file in the Lambda console‘s function code editor.

To test, you can either wait for the scheduled CloudWatch Event to trigger the function, or manually invoke it with a test event in the Lambda console.

If all goes well, you should see your Hacker News digest posted to your specified Slack channel at the scheduled time!

Additional Considerations

Error Handling and Logging

In a production application, you‘ll want robust error handling and logging. Use try/catch blocks to handle potential errors, and log useful information with console.log or a logging library. AWS Lambda automatically logs output from console.log to CloudWatch Logs.

Security

Always be cautious when dealing with third-party APIs and webhooks. Use environment variables for sensitive data like API keys and webhook URLs, rather than hardcoding them. Regularly rotate API keys and webhook URLs. Set the minimum necessary permissions for your Lambda function‘s IAM role.

Extending the Idea

Scheduling Slack messages is just one example of the many tasks that can be automated with serverless functions. You could adapt this to send digest emails, database cleanup, generating reports, or any number of tasks that need to happen on a regular schedule.

You could also enhance the Slack messages with more advanced formatting, interactive components like buttons and menus, or conditionally sending messages based on certain thresholds or criteria.

Conclusion

AWS Lambda and serverless computing open up a world of possibilities for automating tasks in a scalable, cost-effective way. By triggering Lambda functions on a schedule with CloudWatch Events, we can replace cron jobs that would have traditionally required a dedicated server running 24/7.

In this post, we walked through an example of using Lambda to send scheduled Slack messages with top stories from Hacker News. I hope this has given you some ideas for how you can leverage serverless in your own projects!

Remember, with great power comes great responsibility. Use your scheduled Lambda powers for good, and always keep an eye on your AWS bill. Happy coding!

Similar Posts