Zack Chase 5ab3d65926 Add markdown linting (#2135)
* Add markdown linting script; fix markdown lint errors

* Add support for meta description and page title validation

* Add comments

* Fix lint errors; exclude autogenerated tutorials

* Address feedback; add more comments

* Add more checks for redirect pages; no index; and auto generated content

* More fixes for lint errors

* Allow duplicate headings in a page

* More lint error fixes

* Even more lint error fixes

* Getting started guide lint fixes

* Add custom h1 support to docs single pages

* Use custom h1 tags on cloud getting started guides

* Add custom h1 support to docs

* Add custom h1 support to docs lists.html

* Final round of intial lint fixes

* Add markdown linting to build script

* Update README

* Test build failure due to lint error

* Fix lint error so build will pass

* Readability fixes for lint script
2019-12-18 09:59:20 -08:00

184 lines
9.2 KiB
Markdown

---
title: "Using Pulumi with AWS SQS and Lambdas"
authors: ["cyrus-najmabadi"]
tags: ["JavaScript","Serverless","AWS"]
date: "2018-07-10"
meta_desc: "Learn how to use Amazon's SQS with Pulumi in order to post a Slack notification upon receipt of a message via SQS."
---
[Two weeks ago](https://aws.amazon.com/blogs/aws/aws-lambda-adds-amazon-simple-queue-service-to-supported-event-sources/)
Amazon added [Simple Queue Service](https://aws.amazon.com/sqs/) (SQS)
as a supported event source for
[Lambda](https://aws.amazon.com/lambda/). SQS is one of AWS's oldest
services, providing access to a powerful message queue that can do
things like guarantee messages will be delivered at least once, or
messages that will be processed in the same order they were received in.
Adding SQS as a supported event source for Lambda means that now it's
possible to use SQS in a serverless computing infrastructure, where
Lambdas are triggered in response to messages added to your SQS queue.
Now, instead of needing some sort of Service dedicated to polling your
SQS queue, or creating [Simple Notification Service](https://aws.amazon.com/sns/) (SNS)
notifications from your
messages, you can instead just directly trigger whatever Lambda you
want.
<!--more-->
## Example: Using AWS SQS and Lambda to post messages to Slack
Here's a simple example of using SQS as an event source with Pulumi:
upon receipt of a message via SQS we post a new message into Slack. The
full project is available on Github in our
[examples repo](https://github.com/pulumi/examples/tree/master/aws-js-sqs-slack),
and includes the instructions to get this up and running.
```javascript
let aws = require("@pulumi/aws");
let serverless = require("@pulumi/aws-serverless");
let config = require("./config");
let queue = new aws.sqs.Queue("mySlackQueue", { visibilityTimeoutSeconds: 180 });
serverless.queue.subscribe("mySlackPoster", queue, async (e) => {
let slack = require("@slack/client");
let client = new slack.WebClient(config.slackToken);
for (let rec of e.Records) {
await client.chat.postMessage({
channel: config.slackChannel,
text: `*SQS message ${rec.messageId}*: ${rec.body}`+
`(with :love_letter: from Pulumi)`,
as_user: true,
});
console.log(`Posted SQS message ${rec.messageId} to Slack channel ${config.slackChannel}`);
}
}, { batchSize: 1 });
module.exports = {
queueURL: queue.id,
};
```
## Implementing SQS in Pulumi
When we heard about this new functionality, we immediately knew we
wanted to let people access this new power from their Pulumi
applications. Based on Amazon's documentation on this new capability we
felt it would likely be very easy to provide. Amazon introduced this
functionality by reusing existing systems and APIs. Specifically, to
create a Lambda trigger off an SQS message you only need to create a new
[Event Source Mapping](https://docs.aws.amazon.com/lambda/latest/dg/API_CreateEventSourceMapping.html)
mapping between the two. This seemed like it would be very simple, and
we set off to expose the right Pulumi API to make this possible.
[@pulumi/aws-serverless](https://github.com/pulumi/pulumi-aws-serverless)
is Pulumi's convenience library for creating
[Serverless](https://aws.amazon.com/serverless/) computing components.
And we added the necessary code to expose the functionality in our
simple Pulumi programming model
[here](https://github.com/pulumi/pulumi-aws-serverless/blob/master/nodejs/aws-serverless/queue.ts).
With this new API you would now be able to write code in your Pulumi
application like so:
```javascript
import * as aws from "@pulumi/aws";
import * as serverless from "@pulumi/aws-serverless";
// Create the queue. Provide whatever specific configuration you need here.
const sqsQueue = new aws.sqs.Queue("queue", {
visibilityTimeoutSeconds: 300,
});
// Set up a subscription that will fire whenever the queue receives a message. Here we ask
// for 'batchSize = 1' so we will only process a single message at a time.
serverless.queue.subscribe("subscription", sqsQueue, async (event) => {
// Add whatever code you want here to run in the AWS lambda. 'event' will contain the
// all the necessary data about the message added to the queue.
}, { batchSize: 1 });
```
This example also demonstrates several of the great capabilities of a
Pulumi application. First, the ability to define your infrastructure
directly in code (i.e. the AWS Queue, Lambda, and Event Subscriptions),
instead of needing to do that separately. Second, the ability to avoid
needing to specify every single AWS resource necessary to get up and
running. For example, I did not have to supply explicit Roles,
Role-Policy-Attachments, or Permissions here as Pulumi took care of that
for me by default. Third, the ability to create an AWS Lambda directly
from a JavaScript/TypeScript arrow-function. That `async (event) => ...`
is written in code as a normal async-arrow-function, but it will be
converted by Pulumi into all the machinery necessary to have a true AWS
Lambda running in your infrastructure.
After adding the API and writing up a simple app to test things, we then
ran a `pulumi update` to deploy our application to AWS. Unfortunately,
we immediately ran into a problem:
```
Plan apply failed:
Error creating Lambda event source mapping: ValidationException: 1 validation error detected: Value '' at
'startingPosition' failed to satisfy constraint: Member must satisfy enum value set:
[LATEST, AT_TIMESTAMP, TRIM_HORIZON]
```
So what happened? Well, as it turns out, Pulumi leverages and integrates
with many other amazing Open Source projects under the covers. In this
case, it was our integration with [Terraform](https://www.terraform.io/)
that was causing this small snag. It turns out that while Amazon relaxed
their API to no longer have that constraint on 'startingPosition',
Terraform was still referencing an older awssdk API that still contained
that constraint.
At Pulumi we think that Terraform is fantastic, and we love using it. So
we thought the best thing we could do in this position was to help out
that project to support this new functionality as well. We did this
around two weeks ago by contributing [this PR](https://github.com/terraform-providers/terraform-provider-aws/pull/5024)
to their project. We worked with Terraform over a couple over a few days
to get the PR up to snuff, and eventually got it in. With this, now both
Terraform and Pulumi customers will be able to benefit from these
changes in the upcoming releases for both projects!
After getting the change in we went back and tested our example and saw
that now everything worked as expected. We also expanded things out
[in an example](https://github.com/pulumi/pulumi-aws/blob/master/examples/queue/index.ts)
to show how you might use this in practice. In this example, we receive
the event, and then just write the data of it into an [S3 Bucket](https://aws.amazon.com/s3/). Running this example we now
successfully see:
```
pulumi update
Updating stack 'cysqstest'
Performing changes:
Type Name Status
+ pulumi:pulumi:Stack queue-cysqstest created
+ ├─ aws:serverless:Function subscription-queue-subscription created
+ │ ├─ aws:iam:Role subscription-queue-subscription created
+ │ ├─ aws:iam:RolePolicyAttachment subscription-queue-subscription-32be53a2 created
+ │ ├─ aws:iam:RolePolicyAttachment subscription-queue-subscription-7cd09230 created
+ │ └─ aws:lambda:Function subscription-queue-subscription created
+ ├─ aws:sqs:Queue queue created
+ ├─ aws:s3:Bucket testbucket created
+ └─ aws-serverless:queue:QueueEventSubscription subscription created
+ ├─ aws:lambda:Permission subscription created
+ └─ aws:lambda:EventSourceMapping subscription created
info: 11 changes performed:
+ 11 resources created
Update duration: 28s
```
Once created, we could then see this Stack at <https://app.pulumi.com>,
and we could easily use the functionality there to even navigate to
those resources over at our [AWS Console](https://console.aws.amazon.com). Over there were were able to
use the console to both send a message to the Queue, verify our Lambda
got triggered, and even check our Bucket to see the data written into
it. In only around a dozen lines of code, we were able to provision 11
AWS resources, and create a real end-to-end Serverless message-receiving
and processing pipeline. Now, we can expand on this functionality with
more resources or more functionality, run `pulumi update` and just
simply and safely update our cloud infrastructure!
You'll see this functionality lighting up in our next release of
`@pulumi/pulumi` and `@pulumi/aws-serverless`. We hope it helps you out
and makes your cloud life that much easier. Happy coding!