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

How do I handle several retried events only once? #868

Closed
haithcockce opened this issue Mar 20, 2023 · 8 comments
Closed

How do I handle several retried events only once? #868

haithcockce opened this issue Mar 20, 2023 · 8 comments
Labels
auto-triage-stale question Further information is requested

Comments

@haithcockce
Copy link

Hey all, thank you for all the work on this python client. It definitely makes scripting a slackbot really easy.

I have an occasional issue where my slack bolt app receives an event after the 3 second timeout causing the app to receive the same event multiple times. This occurs as well for basic things such as someone asking my app to post a slack message with a basic help message (IE quite truly just replying back with some basic strings). I can confirm this timing by enabling debugging logging.

How do I go about acknowledging an event once and ignoring the retries in the event this happens?

Some additional context;

  • I'm running slack bolt in socket mode
  • I'm handling only message events, e.g. @app.event('message')

Reproducible in:

$ pip freeze | grep slack && python --version
slack-bolt==1.16.1
slack-sdk==3.19.5
Python 3.10.6

The slack_bolt version

slack-bolt==1.16.1

Python runtime version

Python 3.10.6

OS info

Fedora 35

@WilliamBergamin
Copy link
Contributor

WilliamBergamin commented Mar 20, 2023

Hi @haithcockce thanks for writing in 💯

Bolt python provides a way to Acknowledge a request through the Ack argument. Would you be able to ensure that the ack() function is called as the first step in your message handling

here is an example

@app.event('message')
def sample_action_callback(ack: Ack, client: WebClient, logger: Logger):
    try:
        ack()
        client.chat_postMessage...
        ...
    except Exception as e:
        logger.error(e)

@WilliamBergamin WilliamBergamin added the question Further information is requested label Mar 20, 2023
@seratch
Copy link
Contributor

seratch commented Mar 20, 2023

@haithcockce To ignore retried requests, you can check the existence of the following in your global middlware or listener functions:

  • When you run your app serving Request URL, the "x-slack-retry-num" request header can exist
  • When you run your app with Socket Mode, retry_attempt can exist as a top-level property in body

@haithcockce
Copy link
Author

@WilliamBergamin Thank you for that! I will keep this in mind should I need it at some point.

@seratch Thank you! I will dig into the body tomorrow and see if simply checking for this will suffice.

@jonfairbanks
Copy link

jonfairbanks commented Apr 4, 2023

Something is definitely strange with ack() behavior. Checkout these samples...

Using this middleware setup, it works as expected and messages do not replay:

import json
import os
import sys
import time
from log_config import logger
from slack_bolt import App
from slack_bolt.adapter.socket_mode import SocketModeHandler

# Setup Slack app
app = App(
    token=os.environ.get("SLACK_BOT_TOKEN"),
    signing_secret=os.environ.get("SLACK_SIGNING_SECRET"),
)

# Middleware
@app.middleware
def middleware(body, next):
    return next()


# Catch all (should be last handler)
@app.event("message")
def handle_message_events(body):
    logger.debug('message')
    logger.debug(body)
    pass


if __name__ == "__main__":
    try:
        with SocketModeHandler(app, os.environ["SLACK_APP_TOKEN"]).start():
            pass
    except KeyboardInterrupt:
        sys.exit(130)
    except Exception:
        sys.exit(1)

If anything in the middleware takes longer than 3 seconds, all messages will replay multiple times:

import json
import os
import sys
import time
from log_config import logger
from slack_bolt import App
from slack_bolt.adapter.socket_mode import SocketModeHandler

# Setup Slack app
app = App(
    token=os.environ.get("SLACK_BOT_TOKEN"),
    signing_secret=os.environ.get("SLACK_SIGNING_SECRET"),
)

# Middleware
@app.middleware
def middleware(ack, body, next):
    ack()
    try:
        pass
        logger.debug('middleware')
        logger.debug(body)
        time.sleep(5)
    except Exception as e:
        logger.error(f"⛔ Event error: {e}")
    return next()


# Catch all (should be last handler)
@app.event("message")
def handle_message_events(ack, body):
    ack()
    logger.debug('message')
    logger.debug(body)
    pass


if __name__ == "__main__":
    try:
        with SocketModeHandler(app, os.environ["SLACK_APP_TOKEN"]).start():
            pass
    except KeyboardInterrupt:
        sys.exit(130)
    except Exception:
        sys.exit(1)

The ack() call is the very first thing to take place in the middleware so why does it act like this has not occurred?

I have also found mentions that there is a value that can be parsed to bypass retries, but these values do not seem to be valid. This function always returns {}.

@jonfairbanks
Copy link

Spent some more time on this tonight. I think the issue is trying to ack() in middleware. If you move the ack out into message or app_mention events it seems to work fine.

@WilliamBergamin
Copy link
Contributor

Based on the definition of the Middleware ack is not provided as an input parameter to the process method, this is most likely why nothing happens when calling ack() from a middleware

Hope this helps!

@github-actions
Copy link

github-actions bot commented May 8, 2023

👋 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.

@github-actions
Copy link

As this issue has been inactive for more than one month, we will be closing it. Thank you to all the participants! If you would like to raise a related issue, please create a new issue which includes your specific details and references this issue number.

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

4 participants