Skip to content

Using serverless-offline with Lazy Listeners #556

@JordanGibson

Description

@JordanGibson

Reproducible in:

slack-sdk==3.13.0
Python 3.8.8
ProductName:	macOS
ProductVersion:	12.0
BuildVersion:	21A5506j
Darwin Kernel Version 21.1.0: Thu Aug 19 02:54:44 PDT 2021; root:xnu-8019.40.29~26/RELEASE_ARM64_T8101

Steps to reproduce:

(Share the commands to run, source code, and project settings (e.g., setup.py))

  1. Execute the source code documented below, and try to run with sls offline
  2. When hitting the handler via a slack invocation, an error is thrown when running the lazy listener (see stack trace below)
Failed to run a middleware middleware (error: An error occurred (ResourceNotFoundException) when calling the Invoke operation: Function not found: arn:aws:lambda:eu-west-1:673319237159:function:Fake)
Traceback (most recent call last):
  File "/Users/jordangibson/Source/python/slack-message-handler/venv/lib/python3.8/site-packages/slack_bolt/app/app.py", line 545, in dispatch
    ] = self._listener_runner.run(
  File "/Users/jordangibson/Source/python/slack-message-handler/venv/lib/python3.8/site-packages/slack_bolt/listener/thread_runner.py", line 102, in run
    self._start_lazy_function(lazy_func, request)
  File "/Users/jordangibson/Source/python/slack-message-handler/venv/lib/python3.8/site-packages/slack_bolt/listener/thread_runner.py", line 194, in _start_lazy_function
    self.lazy_listener_runner.start(function=lazy_func, request=copied_request)
  File "/Users/jordangibson/Source/python/slack-message-handler/venv/lib/python3.8/site-packages/slack_bolt/adapter/aws_lambda/lazy_listener_runner.py", line 27, in start
    invocation = self.lambda_client.invoke(
  File "/Users/jordangibson/Source/python/slack-message-handler/venv/lib/python3.8/site-packages/botocore/client.py", line 391, in _api_call
    return self._make_api_call(operation_name, kwargs)
  File "/Users/jordangibson/Source/python/slack-message-handler/venv/lib/python3.8/site-packages/botocore/client.py", line 719, in _make_api_call
    raise error_class(parsed_response, operation_name)
botocore.errorfactory.ResourceNotFoundException: An error occurred (ResourceNotFoundException) when calling the Invoke operation: Function not found: arn:aws:lambda:eu-west-1:673319237159:function:Fake

Expected result:

The lazy listener function to be invoked as expected

Actual result:

The application crashes and errors out, responding with a 500 Internal Error

Requirements

Please read the Contributing guidelines and Code of Conduct before creating this issue or pull request. By submitting, you are agreeing to those rules.

Observations

This is reproducible locally using serverless-offline, however when I deploy it to aws lambda, I receive a similar (although different) error. Looks to be permissions related, but also seems to be failing on the same issue so I thought I'd include it here in case it's possibly related

2021-12-27 04:49:28,775 Failed to run a middleware middleware (error: An error occurred (AccessDeniedException) when calling the Invoke operation: User: arn:aws:sts::673319237159:assumed-role/slack-message-handler-dev-eu-west-1-lambdaRole/slack-message-handler-dev-hello is not authorized to perform: lambda:InvokeFunction on resource: arn:aws:lambda:eu-west-1:673319237159:function:slack-message-handler-dev-hello because no identity-based policy allows the lambda:InvokeFunction action)

Traceback (most recent call last):
File "/var/task/slack_bolt/app/app.py", line 545, in dispatch
    ] = self._listener_runner.run(
File "/var/task/slack_bolt/listener/thread_runner.py", line 102, in run
    self._start_lazy_function(lazy_func, request)
File "/var/task/slack_bolt/listener/thread_runner.py", line 194, in _start_lazy_function
    self.lazy_listener_runner.start(function=lazy_func, request=copied_request)
File "/var/task/slack_bolt/adapter/aws_lambda/lazy_listener_runner.py", line 27, in start
    invocation = self.lambda_client.invoke(
File "/var/task/botocore/client.py", line 391, in _api_call
    return self._make_api_call(operation_name, kwargs)
File "/var/task/serverless_sdk/vendor/wrapt/wrappers.py", line 602, in __call__
    return self._self_wrapper(self.__wrapped__, self._self_instance,
File "/var/task/serverless_sdk/__init__.py", line 499, in wrapper
    raise error
File "/var/task/serverless_sdk/__init__.py", line 495, in wrapper
    response = wrapped(*args, **kwargs)
File "/var/task/botocore/client.py", line 719, in _make_api_call
    raise error_class(parsed_response, operation_name)

botocore.exceptions.ClientError: An error occurred (AccessDeniedException) when calling the Invoke operation: User: arn:aws:sts::673319237159:assumed-role/slack-message-handler-dev-eu-west-1-lambdaRole/slack-message-handler-dev-hello is not authorized to perform: lambda:InvokeFunction on resource: arn:aws:lambda:eu-west-1:673319237159:function:slack-message-handler-dev-hello because no identity-based policy allows the lambda:InvokeFunction action

handler.py

import logging
import time

from slack_bolt import App
from slack_bolt.adapter.aws_lambda import SlackRequestHandler

# process_before_response must be True when running on FaaS
app = App(process_before_response=True)


@app.middleware  # or app.use(log_request)
def log_request(logger, body, next):
    logger.debug(body)
    return next()


command = "/hello-bolt-python-lambda"


def respond_to_slack_within_3_seconds(body, ack):
    if body.get("text") is None:
        ack(f":x: Usage: {command} (description here)")
    else:
        title = body["text"]
        ack(f"Accepted! (task: {title})")


def process_request(respond, body):
    time.sleep(5)
    title = body["text"]
    respond(f"Completed! (task: {title})")


app.command(command)(ack=respond_to_slack_within_3_seconds, lazy=[process_request])

SlackRequestHandler.clear_all_log_handlers()
logging.basicConfig(format="%(asctime)s %(message)s", level=logging.DEBUG)


def main(event, context):
    slack_handler = SlackRequestHandler(app=app)
    return slack_handler.handle(event, context)

serverless.yml

service: slack-message-handler
app: slack-message-handler
org: jgibson37

frameworkVersion: '2'

provider:
  name: aws
  runtime: python3.8
  lambdaHashingVersion: 20201221
  region: eu-west-1
  environment:
    SLACK_BOT_TOKEN: ${env:SLACK_BOT_TOKEN}
    SLACK_SIGNING_SECRET: ${env:SLACK_SIGNING_SECRET}

functions:
  slack-message-handler:
    handler: handler.main
    events:
      - http:
          path: slack/events
          method: post

plugins:
  - serverless-python-requirements
  - serverless-offline
custom:
  pythonRequirements:
    dockerizePip: non-linux
  serverless-offline:
    noPrependStageInUrl: true

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions