Test for running probot in AWS Lambda
:wave: Archiving this in favor of the new extension published in the Probot Org that doesn't use babel/webpack, and builds off the move to TypeScript in Probot 7: https://github.com/probot/serverless-lambda
Feel free to test that out and open issues over there!
This is a demonstration for how to run the Probot framework on Lambda. Due the event driven nature of bots, running Probot in a "serverless" environment can make a lot of sense. The GitHub App's Webhook just needs to point to a URL on API Gateway to receive the events, and Lambda will run the bot's logic without having to manage servers.
$ git clone https://github.com/tcbyrd/probot-lambda.git
$ npm install
$ npm install -g serverless
Note: Also ensure your AWS Credentials are configured. See the Serverless Docs for more info.
Create the 'Webhook Secret' and assign it to an environment variable with the name WEBHOOK_SECRET
On your app's Basic info screen, find the ID
and assign this to an environment variable with the name APP_ID
serverless.yml
file nested under functions: probot: environment:
orupdate-function-cofiguration
method:# Example
aws lambda update-function-configuration --function-name lambda-probot-dev-probot --environment "Variables={APP_ID=0000,WEBHOOK_SECRET=development}"
Put the generated Private Key in the root directory with the filename private-key.pem
$ serverless deploy
endpoints:
POST - https://9zzzz99999.execute-api.us-east-1.amazonaws.com/dev/probot
This demo app is a simple auto-responder plugin that sends a nice thank you message when anyone opens an issue on the installed repository.
The Robot
class in Probot implements an event emitter already, so getting this wired up to Lambda is relatively simple. Calling webhook.emit
directly, you can pass the data coming from the HTTP Request directly to your Probot plugin:
module.exports.probotHandler = function (event, context, callback) {
const e = event.headers['X-GitHub-Event']
probot.robot.webhook.emit(e, {
event: e,
id: event.headers['X-GitHub-Delivery'],
payload: JSON.parse(event.body)
})
}
There are a few different tools that help with testing to deploying serverless applications to AWS, but in general they all do a few things:
The Serverless Framework is what's being demonstrated here, chosen mainly because of its solid documentation, ecosystem of plugins, and its active community.
If you've never built a web application with serverless architectures, the important thing to understand is that Lambda functions are only a piece of that puzzle. There are a number of events that can trigger a function. For web applications, you'll also need to provision an API Gateway endpoint that triggers the function. The Serverless Framework handles this for you by allowing you to specify the http endpoint and method in serverless.yml
as an event handler for the Probot function.
By default, Serverless uses Lambda-Proxy, meaning it passes the entire HTTP request to the handler as an event
. This allows Probot to process the headers and payload of the webhook just like it does on the server. However, it does transform the body of the request, so the payload must be parsed in the function before being processed by your plugin. Hence, the presence of payload: JSON.parse(event.body)
in the example above.
async/await
in AWS LambdaProbot requires NodeJS v7.7 and makes use of async/await
. Since Lambda's NodeJS runtime currently uses v6.10, it doesn't natively handle this syntax. Luckily, there are some tools to help with this.
There's a lot to these tools that you can learn from the above links, but the TL;DR is this: Webpack looks at all the NodeJS modules in the root directory (in this case, skipping the entire node_modules
directory) and bundles them into a single file.
While it's loading the modules, it can also transform them with Babel to work with older versions of Javascript. Generally used on the front-end to take advantage of newer features in JS in older browsers, this is also useful on the server for supporting the same new features in older versions of NodeJS.
The serverless-webpack
plugin allows you to specify this transpilation step in the serverless.yml
file. This makes it possible to keep using async/await
in Probot and your Probot plugins, transpile the functions to work with NodeJS v6.10, and deploy to Lambda with a single command: sls deploy
.
The specific webpack configuration is located in webpack.config.js
and it uses .babelrc
to specify the babel presets and plugins. Additionally, to keep from having to bundle all of Probot's dependencies, it ignores the node_modules
folder and instead bundles Probot from the root directory. This helps mitigate bugs that sometimes get introduced when attempting to bundle modules intended for server-side use.