Realize asynchronous Slack slash command with AWS serverless

Chen-Che Huang
5 min readMar 28, 2020

--

Slack is one of the most popular team collaboration software nowadays. Besides instant messaging, Slack provides many apps and supports custom apps to fulfill various requirements. To invoke a custom app, one entry point is slash commands that enable users to run the custom app by simply typing a string on a channel. Explicitly, what a slash command does is to send an HTTP request with the user input to the web endpoint of the associated custom app. Slash commands empower users to accomplish a variety of tasks on Slack channels as long as the corresponding web apps are well implemented.

Service deployment as an example

In this post, I’d like to introduce how to create a slash command to deploy new versions of services on AWS ECS. Taking service deployment as an example is because it’s common for software engineers. Although deployment should be done via CI/CD tools (e.g., Gitlab CI/CD and Jenkins), using the slash command has two main benefits.

  1. The deployment actions and results are visible to and traceable for all the stakeholders.
  2. The deployment is more convenient. Developers can do deployment/rollback easily by simply typing a few words on their mobile phones. QA are able to do the deployment to verify issues with specific versions when necessary without understanding the CI/CD tools.

Before proceeding, I’d like to remind that this example is for demonstration and is probably useful in the development or staging environment. However, I don’t suggest to adopt this approach to the production environment.

To realize this feature, we need to create a slash command and a web application with permissions to run the deployment. Creating a slash command is fairly simple by following Slack’s guide. Assume we create a slash command named /ecs_deploy with two parameters <service> and <version>. When a user runs/ecs_deploy <service> <version> on a channel, the corresponding web app shall start to update <service> with version and return the result to the same channel.

Because the slash command is for people instead of bots, it’s ideal to implement this web app with AWS serverless services because 1) the usage frequency is low and 2) performance and latency are not a concern. AWS serverless enables developers to run the applications without managing or operating the underlying infrastructure. With AWS serverless, we don’t need a long-running ec2 instance (which is idle most of the time) and just pay for what we really use. If you haven’t heard of AWS serverless, you may take a look at the AWS doc for a better understanding of this post.

Design and implementation of the service

Considering basic requirements and the characteristics of slash commands, this web app supports the following features.

  • Command authentication. To make the app secure, we must do authentication by at least verifying the token of the slash command. I’d suggest to limit this slash command to be issued only on one dedicated channel by checking the channel_id. Slack also provides other information like user_id for stricter authentication if needed.
  • Asynchronous response. When a slash command sends an HTTP request, it expects the response to be received within 3 seconds. Otherwise, the user invoking the command will see Timeout was reached. Thus, this web app must support asynchronous calls by sending the response to the response_url given in the request body and setting {“response_type": “in_channel", “text": message} to the response body.
  • Malformed parameters handling. Slash commands store the parameters as a string in the text field of the request body. The parameters are separated by a whitespace which will be replaced with + in the request body. For example, the parameters of /command para1 para2 para3 would be transformed to para1+para2+para3 and stored in the value of text. The behavior of using whitespaces as delimiters is often confusing and ignored by users. Thus, the app should handle this case in a user-friendly manner.
Serverless web app provisioned by CDK

Based on the design and implementation considerations, this web app is realized with the above system architecture where each component is described below.

  • API Gateway. The AWS API Gateway serves as the entrypoint for HTTP requests from our slash command /ecs_deploy <service> <version>. Upon receiving requests, the API Gateway invokes the request validator to do verification.
  • Request validator (lambda). The request validator, implemented as an AWS Lambda function, is responsible for checking whether the token and channel_id are expected as well as the parameters are valid. If so, the request validator sends the request to the request bridge and returns 200 OK to Slack. By replying to Slack immediately and passing the request event to the request bridge, we can achieve the asynchronousness and address the 3 seconds limit.
  • Request bridge (SNS topic). The request bridge, implemented as an AWS SNS topic, acts as a bridge to pass the event message from the request validator to the request handler.
  • Request handler (lambda). The request handler, also an AWS lambda function, runs the ECS deployment task based on <service>and <version>. When the deployment is completed, the request handler sends the result back to the channel via the response_url. Note that the maximum execution time of a lambda function is 15 minutes that is sufficiently long for the majority of tasks like this one. However, if you’d like apply the architecture in this post for longer tasks, you shall consider to use AWS Step Functions.
  • CDK. To build the entire system, we use AWS CDK which enables developers to define the AWS resources in the programming language and provisions the resources through AWS CloudFormation. With CDK, you can do infrastructure as code more concisely than CloudFormation because CDK does lots of transformations behind the scene.

Build the system with AWS CDK

To build the serverless system with CDK, we create a CDK Python app named serverless_ecs_deploy. The code snippet above is the procedure of using this CDK app to deploy the system. First, the initialization command cdk init --language python creates the directory structure and associated files. We then write the lambda functions serverless_ecs_deploy/request_validator.py and serverless_ecs_deploy/request_handler.py for the request validator and the request handler, respectively. In serverless_ecs_deploy/serverless_ecs_deploy_stack.py, we declare and associate the objects of the AWS resources in this serverless app. From the code of the serverless_ecs_deploy_stack.py, you can see we can easily use objects to reflect the system architecture with AWS CDK. After we write the three core scripts, we can use cdk synth to review the corresponding CloudFormation template which is actually used to provision the system. Finally, we run cdk deploy to trigger the provisioning of the system defined in serverless_ecs_deploy_stack.py. If everything is fine, the outputs of cdk deploy shows the endpoint of this web app like serverless-ecs-deploy.serverlessecsdeployEndpoint2ADDF30F = https://ww21uy5vp4.execute-api.us-east-1.amazonaws.com/prod/. This is the request url for our slash command /ecs_deploy <service> <version>.

serverless_ecs_deploy app structure

Summary

As more collaboration and communications happen in Slack channels, using Slack slash commands is not only convenient for addressing various tasks but also makes things visible to and traceable for channel members. With AWS serverless, we can realize slash commands at almost no cost. This post intends to demonstrate the benefits and simplicity of combining Slack slash commands and AWS serverless for certain tasks. Welcome to leave your comments if any.

--

--

No responses yet