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

Lazy Listener Error: NoneType #1217

Open
freyguy opened this issue Dec 5, 2024 · 7 comments
Open

Lazy Listener Error: NoneType #1217

freyguy opened this issue Dec 5, 2024 · 7 comments
Assignees
Labels
auto-triage-stale question Further information is requested

Comments

@freyguy
Copy link

freyguy commented Dec 5, 2024

I'm attempting to use the Slack Bolt Python Lazy Listener function to handle the initial ack() and then run a longer process to interact with secondary systems. I've had success without using the Lazy Listener function in just acknlowedging the response and writing back to the initial user, but whenever I introduce the Lazy Listener function in a testing manner I'm routinely encountering the same error

I was using this article as a template for configuring my application.

Reproducible in:

pip freeze | grep slack
python --version
sw_vers && uname -v # or `ver`

The slack_bolt version

slack-bolt==1.18.1

Python runtime version

Python 3.11.6

OS info

ProductName: macOS
ProductVersion: 14.7.1
BuildVersion: 23H222
zsh: command not found: ver

Steps to reproduce:

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

import boto3
import json
import time
import os
from slack_bolt import App
from slack_bolt.adapter.aws_lambda import SlackRequestHandler

def get_secret(secret_name):
    # Create a Secrets Manager client
    client = boto3.client("secretsmanager")
    try:
        # Retrieve the secret
        response = client.get_secret_value(SecretId=secret_name)
        # Check if the secret is stored as plain text or JSON
        if "SecretString" in response:
            secret = response["SecretString"]
            return json.loads(secret)  # If the secret is JSON
        else:
            # If it's binary data
            return json.loads(response["SecretBinary"])
    except Exception as e:
        print(f"Failed to retrieve secret: {e}")
        raise e

slack_signing_secret = get_secret('SLACK_SIGNING_SECRET')
slack_bot_token = get_secret('SLACK_BOT_TOKEN')

app = App(
    # process_before_response=True,
    token = slack_bot_token,
    signing_secret = slack_signing_secret)


def acknowledge(ack):
    ack()

def default_message_handler():
    print("Default message handler hit")

## Lazy listener function
@app.action("first_response")(ack=acknowledge, lazy=[default_message_handler])

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

Expected result:

I expect the ack of the response, and my logging to print the lazy function. However the original message is left unacknowledged with the ability to repeat button responses over and over as the response hasn't been ack'd and the following error is produced rather than my logging showing the printing of the lazy function.

I've verified secrets are returned as expected and that the button id is correct.

Actual result:

[ERROR] TypeError: 'NoneType' object is not callable Traceback (most recent call last):   File "/var/lang/lib/python3.13/importlib/__init__.py", line 88, in import_module     return _bootstrap._gcd_import(name[level:], package, level)   File "<frozen importlib._bootstrap>", line 1387, in _gcd_import   File "<frozen importlib._bootstrap>", line 1360, in _find_and_load   File "<frozen importlib._bootstrap>", line 1331, in _find_and_load_unlocked   File "<frozen importlib._bootstrap>", line 935, in _load_unlocked   File "<frozen importlib._bootstrap_external>", line 1022, in exec_module   File "<frozen importlib._bootstrap>", line 488, in _call_with_frames_removed   File "/var/task/lambda_function.py", line 50, in <module>     @app.action("first_response")(ack=acknowledge, lazy=[default_message_handler])
Link 
[ERROR] TypeError: 'NoneType' object is not callable
Traceback (most recent call last):
  File "/var/lang/lib/python3.13/importlib/__init__.py", line 88, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1387, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1360, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1331, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 935, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 1022, in exec_module
  File "<frozen importlib._bootstrap>", line 488, in _call_with_frames_removed
  File "/var/task/lambda_function.py", line 50, in <module>
    @app.action("first_response")(ack=acknowledge, lazy=[default_message_handler])

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.

@hello-ashleyintech hello-ashleyintech self-assigned this Dec 5, 2024
@hello-ashleyintech
Copy link

Hi, @freyguy! Looks like you commented out process_before_response=True for your app config, but this is needed for lazy listeners, as seen here.

Let me know if this is causing the issue - if not, we can troubleshoot further!

@seratch
Copy link
Member

seratch commented Dec 5, 2024

@freyguy In this case, you don't use the method decorator provided by App. So, your @app.action in your code must be app.action instead.

@seratch seratch added the question Further information is requested label Dec 5, 2024
@freyguy
Copy link
Author

freyguy commented Dec 6, 2024

@hello-ashleyintech thanks for catching that!

@seratch that seems to drive it to the correct function now and am getting expected results printing in my logs, but I'm still not seeing the message acknowledged in the Slack UI. I'm still able to submit the same response as it seemingly hasn't ack'd the message but I'm not getting a timeout error next to the button.

@seratch
Copy link
Member

seratch commented Dec 6, 2024

If your lamdba execution takes more than 3 seconds (please check AWS's Cloudwatch logs), the runtime performance needs to be adjusted to complete within 3 seconds. A common cause is a cold-start issue with boto3 SDK like this one: #950 (comment) If that's the case, unfortunately there is no workaround on the bolt-python side as boto3 is the bottleneck here. Switching to another solution to load secrets is the only approach I can suggest.

@freyguy
Copy link
Author

freyguy commented Dec 6, 2024

@seratch That should be easy enough to handle with environment variables. Does the lazy function need to also complete within 3 seconds or can that continue to function beyond the 3 second time out for acknowledgement? I'm a bit confused on that portion having read a number of issues folks have had with Bolt/Lambda

@seratch
Copy link
Member

seratch commented Dec 6, 2024

Lazy listeners do not need to complete within 3 seconds. I mean the ack argument function must complete in 3 seconds to avoid the timeout error on the Slack UI.

Copy link

github-actions bot commented Jan 6, 2025

👋 It looks like this issue has been open for 30 days with no activity. We'll mark this as stale for now, and wait 10 days for an update or for further comment before closing this issue out. If you think this issue needs to be prioritized, please comment to get the thread going again! Maintainers also review issues marked as stale on a regular basis and comment or adjust status if the issue needs to be reprioritized.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
auto-triage-stale question Further information is requested
Projects
None yet
Development

No branches or pull requests

3 participants