AWS Lambda

Overview

Sym's AWS Lambda integration is the simplest way to fire off bespoke workflows that manage resources that the Sym platform does not directly integrate with. We'll call your function twice: when we escalate a user after approval, and again on deescalate. All of your SDK Workflow Handlers still apply in the middle, giving you full flexibility to craft workflows around your own last-mile implementations.

Payload

The payload supplied to your Lambda is very similar to that of the Reporting module. You can see a full schema here.

Lambda Templates

Our lambda-templates repo provides a starting point for deploying a Lambda Function which can parse and process incoming payloads from Sym. In that repo, you'll find implementations in Python, Go, and Typescript, as well as a set of test payloads that you can use to test your implementation.

Provisioning an AWS Lambda Strategy

To provision an AWS Lambda Strategy for use in a Flow, define the following resources in Terraform:

# We first create a Permission Context Integration to wrap
# an IAM role which has permission to invoke our Lambda.
resource "sym_integration" "lambda_context" {
  type        = "permission_context"
  name        = "lambda_permission_context"
    # Here we use Sym's AWS IAM connector to provision an IAM role.
  # You could also manually specify the ARN of an existing role.
  settings = module.runtime_connector.settings
}
  
# A Strategy uses an Integration to grant people access to Targets.
resource "sym_strategy" "lambda" {
  type           = "aws_lambda"
  integration_id = sym_integration.lambda_context.id
  targets        = [sym_target.lambda.id]
}

# A Target defines where the payload is sent.
resource "sym_target" "lambda" {
  type  = "aws_lambda_function"
  label = "My Lambda Target"

  settings = {
    arn = "arn:aws:lambda:us-east-1:123456789012:function:my-function"
  }
}

Handling responses

Sym's Lambda Strategy provides an effective way to securely trigger remote processes inside of your VPC. But what if you want to pass responses from your Lambda back to your Sym users?

By returning formatted body and errors attributes to Sym, you can pass information from your remote process back into Sym, pick it up in your Python SDK implementation, and use it in your Flows.

🚧

Responses are required

If you don't include a formatted response from your Lambda, your Flow will succeed, but you will receive a warning message directing you to this guide.

Return formatting

πŸ“˜

These examples are in Python

Your Lambda can be written in any language with a supported runtime. The below examples are all written in Python to align with the Sym SDK.

The return from your Lambda must be formatted as a dict with two keys:

  • body: Dict[str, Any], a dict with one or more string keys
  • errors: List[str], a list of strings

For example:

{
  "body": {
    "message": "this is a custom message I'm going to DM someone!"
  },
  "errors": [] // send an empty array for no errors
}

Errors

Errors in your returned list will be displayed as bullets. For example:

def lambda_handler(event, context):
    print("many magical things are happening here")
    return {
        "body": {
            "message": "A message"
        },
        "errors": [
            "Is this the real life?",
            "Is this just fantasy?",
            "Caught in a landslide",
            "No escape from reality",
        ],
    }

The above return will result in the below error being sent to your Sym Errors channel:

Using Lambda responses in your impl.py

Lambda responses can be retrieved in your Python implementation inside of a Hook that triggers after the Lambda is called:

In both cases, your response output payload can be retrieved via get_step_output().

Best practices

The easiest way to work with your Lambda responses is to treat them like REST responses. Simply grab the payload, throw it in a local variable, and grab the keys off it as you would expect.

from sym.sdk.integrations import slack
from sym.sdk.templates import get_step_output

@hook
def after_escalate(event):
  # Get your Lambda context
  escalate_output = get_step_output()
  
  # Send a Slack message with the body from your output
  slack.send_message(event.user, escalate_output["body"]["message"])

Did this page help you?