Sitelet https://web.archive.org/web/20220108083238/https://github.com/slackapi/bolt-python/issues/556
Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using serverless-offline with Lazy Listeners #556

Open
JordanGibson opened this issue Dec 27, 2021 · 1 comment
Open

Using serverless-offline with Lazy Listeners #556

JordanGibson opened this issue Dec 27, 2021 · 1 comment

Comments

@JordanGibson
Copy link

@JordanGibson JordanGibson commented Dec 27, 2021 •

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
@seratch seratch added this to the 1.x milestone Dec 27, 2021
@seratch seratch changed the title Using Serverless with Lazy Listeners in AWS Lambda Using serverless-offline with Lazy Listeners Dec 27, 2021
@seratch
Copy link
Member

@seratch seratch commented Dec 27, 2021

Hi @JordanGibson, thanks for writing in!

The production deployment error

The cause of the error in your deployed function is due to lack of the permission to invoke the function itself. As mentioned in the document section "Example with AWS Lambda", you need to have the following IAM permissions to run lazy listeners:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "VisualEditor0",
      "Effect": "Allow",
      "Action": [
        "lambda:InvokeFunction",
        "lambda:GetFunction"
      ],
      "Resource": "*"
    }
  ]
}

With the IAM permission, your app should work as you expect. With the serverless framework, please refer to their document for details: https://www.serverless.com/framework/docs/providers/aws/guide/iam

serverless-offline compatibility

We don't support serverless-offline plugin. Although we are open to accepting contributions from the communities (as long as the quality is great enough for long-term maintenance), we are not planning to put efforts on the enhancement on our end. You can find a similar issue here: #490

One suggestion that I can share at this point would be to use Flask for local development. You can switch the main.py like I do in this application: https://github.com/seratch/slack_learning_app_ja

I hope this helps.

@seratch seratch removed the question label Jan 8, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
2 participants