---
title: Lambda Handlers
weight: 3
---

This section assumes you have already created an [SQS Queue]({{< ref "subscribers/sqs_queues.md" >}}), which we'll attach to your Lambda.

## Considerations

Lambda + SQS is an at-least-once delivery system. You'll need to verify that your handlers are idempotent or that duplicate messages won't cause negative side-effects.

Additionally, there are some pros and cons to consider:

#### Pros
1. Easy to set up and deploy
1. Auto-scales based on queue throughput
1. CloudWatch logging is provided "for free"
1. Easy to turn on/off

#### Cons
1. Pay per-invocation gets expensive for high-throughput events
1. Can't rely on any concurrent goroutines/tasks, since AWS manages your process lifecycle
1. No control over process lifecycle, so harder to manage open connections, in-process caching, etc.

For the above reasons, we recommend Lambda as a great way to do early testing of code, or for low-frequency, more "administrative" tasks.

## Setup Guide

This is a quick setup guide to get your Lambda handler running via the AWS console. This is a handy way to do some quick Event Bus testing in a development or staging account.

## Write Your Lambda

For GDPR compliance, our lambda takes the `UserDestroy` event and deletes the user from a hypothetical database.

```go
package main
import (
    "context"
    "log"

    "github.com/aws/aws-lambda-go/lambda"

    eventbus "code.justin.tv/eventbus/client"
    "code.justin.tv/eventbus/client/subscriber/lambdafunc"
    "code.justin.tv/eventbus/schema/pkg/user"
)


func main() {
    mux := eventbus.NewMux()
    user.RegisterDestroyHandler(mux, userDestroyed)

    lambda.Start(lambdafunc.NewSQS(mux.Dispatcher()))
}

func userDestroyed(ctx context.Context, h *eventbus.Header, event *user.Destroy) error {
    log.Printf("User destroyed for compliance: %s", event.UserId)
    _, err := mydb.ExecContext(ctx, "DELETE FROM mytable WHERE user_id=$1", event.UserId)
    return err
}
```

### Build Your Code Package

Assuming you put the above Lambda example in `main.go`, from that directory execute:

    GOOS=linux go build -o ./lambda_handler main.go
    zip handler.zip ./lambda_handler

You'll need this handler.zip later when making the function.

### Create the Lambda in the AWS console

In the AWS Console:

1. Go into the AWS console and click **Services > Compute > Lambda**
1. Make sure the correct region is selected in the top-right corner
1. Click **Create Function**
1. Enter a function name and choose `Go 1.x` for the runtime
1. Under the execution role, select **Create a new role from AWS policy templates** and then **Amazon SQS poller**
1. Click **Create function**

![Create Lambda](../../images/lambda_01_create.png)

After creating the lambda, you'll need to give the Lambda execution role permission to interact with the Event Bus:

1. Go into the AWS console and click **Services > IAM**
1. Click the **Policies** button on the left tab
1. Search for "EventBusAccess" and select it by clicking the circle to the left of its name
1. Click the **Policy actions** dropdown and select **Attach**
1. Search for your Lambda's role and select it by clicking the checkbox to the left of its name
1. Click the **Attach policy** button

### Upload the code

In the Lambda designer, upload your code from the **Function Code** section. Make sure you change your handler name to `lambda_handler` and then upload the zip you made in the [Build Your Code Package]({{< ref "#build-your-code-package" >}}) section.

Alternately, you can do it via the aws-cli with isengard creds:

    aws lambda update-function-code --region us-west-2 \
        --function-name my-lambda-function --zip-file ./handler.zip \
        --publish


### Attach Your Subscription Target

In the Lambda designer, click the **Add Trigger** button, and select **SQS** as the trigger type. Enter the SQS queue for your subscription target, then click **Add**.

![Add trigger](../../images/lambda_03_trigger.png)

## Troubleshooting

The easiest way to check things in a Go Lambda is to log using the stdlib `log` library. This will output to CloudWatch Logs and give you insight into what is happening.

If your Lambda is failing often, there are a few tricks to make it easier to debug:

1. Reduce your Lambda concurrency to **1** to reduce noise during testing
1. Reduce the number of messages fetched from SQS to **1** so each invocation only processes one message at a time
1. Temporarily increase the number of messages required to dead-letter on your queue so you can keep retrying the same messages

### Invocation Problems

If your lambda is not invoking and messages are building up on your SQS queue, try these steps:

1. Make sure your Lambda execution role has permission to send to CloudWatch Logs
1. Check your Lambda execution role has attached the `EventBusAccess` policy
1. If you didn't attach the `EventBusAccess` policy to the Lambda role prior to starting it, then the Lambda's cached credentials could cause failures. Pause the SQS connection to the Lambda using the toggle, apply changes, then re-start the Lambda.
