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

Implement Lazy Listener Functions #34 #35

Merged
merged 6 commits into from
Aug 26, 2020
Merged

Conversation

seratch
Copy link
Member

@seratch seratch commented Aug 7, 2020

Summary

This pull request adds "Lazy Listener Functions" to Bolt for Python. Please refer to #34 for details.

Category (place an x in each of the [ ])

  • slack_bolt.App and/or its core components
  • slack_bolt.async_app.AsyncApp and/or its core components
  • Adapters in slack_bolt.adapter

Requirements (place an x in each [ ])

  • I've read and understood the Contributing Guidelines and have done my best effort to follow them.
  • I've read and agree to the Code of Conduct.
  • I've run ./scripts/run_tests.sh after making the changes.

@seratch seratch added this to the 0.3.0a0 milestone Aug 7, 2020
@seratch seratch self-assigned this Aug 7, 2020
Copy link
Member Author

@seratch seratch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I left a few comments for reviewers.


app.command(command)(
ack=respond_to_slack_within_3_seconds,
lazy=[process_request]
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The process_request method is executed in another Lambda invocation (the same Lambda function). The duplicated request is marked as lazy_only: True and the request contains the name process_request in it.

description: My first lambda function
runtime: python3.8
# role: lambda_basic_execution
role: bolt_python_lambda_invocation # AWSLambdaFullAccess
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To use lazy listener functions feature, the IAM Role should have the permission to invoke Lambda functions.

@@ -85,6 +89,12 @@ async def handle_command(payload, ack, respond, client, logger):
logger.info(res)


app.command("/hello-bolt-python")(
ack=ack_command,
lazy=[post_button_message, open_modal],
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are executed in parallel.

await respond("Loading ...")


async def respond_5_seconds_later(respond):
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't need to (and cannot) call ack() method here as it's a lazy listener function.

@@ -15,6 +18,7 @@ def __init__(self, app: App, chalice: Chalice):
self.app = app
self.chalice = chalice
self.logger = get_bolt_app_logger(app.name, ChaliceSlackRequestHandler)
self.app.lazy_listener_runner = ChaliceLazyListenerRunner(logger=self.logger)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code replaces the default (thread-based) one with Chalice (=Lambda framework by AWS) specific one.

@@ -50,6 +54,15 @@ def handle(self, request: Request):
bolt_resp = oauth_flow.handle_installation(bolt_req)
return to_chalice_response(bolt_resp)
elif method == "POST":
bolt_req: BoltRequest = to_bolt_request(request, body)
# https://docs.aws.amazon.com/lambda/latest/dg/python-context.html
aws_lambda_function_name = self.chalice.lambda_context.function_name
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extracting the AWS Lambda function name for the runner#start method.

"body": request.body,
"isBase64Encoded": False,
}
invocation = self.lambda_client.invoke(
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Invoking the same lambda function with a modified request.

@@ -179,6 +182,10 @@ def __init__(
self._listener_executor = ThreadPoolExecutor(max_workers=5) # TODO: shutdown
self._process_before_response = process_before_response

self.lazy_listener_runner: LazyListenerRunner = ThreadLazyListenerRunner(
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The default runner uses the existing thread executor.

@@ -373,10 +424,11 @@ def event(
matchers: Optional[List[Callable[..., bool]]] = None,
middleware: Optional[List[Union[Callable, Middleware]]] = None,
):
def __call__(func):
def __call__(*args, **kwargs):
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method accepts either of args: [ack_func, lazy_func_1, lazy_func_2] or kwargs {"ack": ack_func, "lazy": [lazy_func_1, lazy_func_2]}

@seratch
Copy link
Member Author

seratch commented Aug 15, 2020

I'll be merging this within a few days (before merging this, I will add more unit tests but don't have anything further to add in the main code). Let me know if you have any comments or feedback by then.

@seratch seratch merged commit 5a702cd into slackapi:main Aug 26, 2020
@seratch seratch deleted the lazy-function branch August 26, 2020 07:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant