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

I would like to refer to X-Slack-Retry-Num. #731

Closed
iwakiri0104 opened this issue Oct 4, 2022 · 8 comments
Closed

I would like to refer to X-Slack-Retry-Num. #731

iwakiri0104 opened this issue Oct 4, 2022 · 8 comments
Labels
question Further information is requested

Comments

@iwakiri0104
Copy link

iwakiri0104 commented Oct 4, 2022

I want to deploy a Slack bolt using Cloud Function, but since I can't use lazy listener, I use Thread for parallel processing. When I deploy to Cloud Function with the following code, I get duplicate messages the first time. After that, it only needs to be done once. However, after some time passes, duplicate messages are sent again.
Therefore, I would like to implement a process that only returns a response if there is an X-Slack-Retry-Num in the header, but I do not know how to get the header.
I implemented the following code in Python this way,

    if "X-Slack-Retry-Num" in event["headers"]:
        return {'statusCode': 200, 'body': 'this request is retry'}

Ended with an error result.

    if "X-Slack-Retry-Num" in event["headers"]:
KeyError: 'headers'

Please let me know if there is a better solution.

### This is my code:

import os
import logging
from slack_bolt import App
from slack_bolt import Say
from slack_bolt.adapter.socket_mode import SocketModeHandler
from slack_sdk import WebClient
import functions_framework
import deepl
import langid
import json
from slack_bolt.adapter.flask import SlackRequestHandler


logging.basicConfig(level=logging.DEBUG)

DEEPL_API_TOKEN = os.environ["DEEPL_API_TOKEN"]
SLACK_BOT_TOKEN = os.environ["SLACK_BOT_TOKEN"]

app = App(
    token=SLACK_BOT_TOKEN,
    signing_secret=os.environ.get("SLACK_SIGNING_SECRET"),
    process_before_response=True
    )
handler = SlackRequestHandler(app)

client = WebClient(SLACK_BOT_TOKEN)
translator = deepl.Translator(DEEPL_API_TOKEN)


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



@app.event("reaction_added")
def show_datepicker(event,say: Say):
    reaction = event["reaction"]
    replies = say.client.conversations_replies(channel=event["item"]["channel"], ts=event["item"]["ts"])
    print("replies is:",replies)
    message = replies["messages"][0]["text"]
    print("message is:",message)
    lang = langid.classify(replies["messages"][0]["text"])
    print("languages[0] is:",lang[0])


    if reaction == "eyes":
        if lang[0] == "ja":
            target_lang = "EN-US"
        elif lang[0] == "en":
            target_lang = "JA"
        else:
            return
        result = translator.translate_text(message, target_lang=target_lang)
        query = ""
        for m in message.split("\n"):
            query += f">{m}\n"
        say(
            thread_ts=replies["messages"][0].get("ts"),
            text=f"{query}{result.text}"
            )           
        return 


from threading import Thread

@functions_framework.http
def slack_bot(request):
    request_data = request.form
    t = Thread(target=show_datepicker, kwargs={'request_data': request_data})
    t.start()
    return handler.handle(request)
    
if __name__ == "__main__":
    app.start(port=int(os.environ.get("PORT", 3000)))

The slack_bolt version

slack-bolt==1.14.3
slack-sdk==3.18.3

Python runtime version

Python 3.9.12

Expected result:

I want to prevent duplicate messages.

Actual result:

Duplicate messages more than three times

@seratch seratch added the question Further information is requested label Oct 4, 2022
@seratch
Copy link
Member

seratch commented Oct 4, 2022

Hi @iwakiri0104, thanks for asking the question! Perhaps, my reply here answered your question, right?

@seratch
Copy link
Member

seratch commented Oct 4, 2022

@iwakiri0104 Relying to #693 (comment)

It seems that you are using Socket Mode. In this case, the retry num value exists as "retry_attempt" in the body.

I've created an issue for enhancement #732 to provide an easier way to access the value in future versions. Until then, please check the Java SDK implementation (slackapi/java-slack-sdk#677) and write your own global middleware to extract the retry properties from Socket Mode payload data.

@iwakiri0104
Copy link
Author

@seratch
Sorry for the misunderstanding. The reason for socket mode is for local testing, and the production environment is intended for FaaS (cloud function).
What I really want to know is why the code here(#639 comment) does not allow me to see the contents of the request.
I thought the above code would allow me to ignore the "X-Slack-Retry-Num", but it seems that I cannot even debug the contents of the request header in the first place.......

@seratch
Copy link
Member

seratch commented Oct 4, 2022

@iwakiri0104 Can you add the following code to your prod app? It should display all the request headers for you.

@app.middleware
def log_request_headers(logger, request, next):
    logger.info(request.headers)
    next()

@iwakiri0104
Copy link
Author

@seratch Thanks to your help, I was able to confirm the "X-Slack-Retry-Num" in the log for the first time!!
I will implement duplicate prevention by referring here. Thank you very much!

@seratch
Copy link
Member

seratch commented Oct 4, 2022

@iwakiri0104 Great to hear that! Let me close this issue now.

@seratch seratch closed this as completed Oct 4, 2022
@eddyg
Copy link
Contributor

eddyg commented Oct 4, 2022

Out of curiosity, aren't the retries being caused by the lack of calling ack(), or am I missing something?

Shouldn't looking at X-Slack-Retry-Num (and ignoring retry messages from Slack servers because it thinks the message has not been properly delivered so it keeps sending them) be considered "bad practice"?

@seratch
Copy link
Member

seratch commented Oct 14, 2022

@eddyg Sorry for my belated response here.

In general, you're right here. In most cases, we don't recommend ignoring retried event delivery. With that being said, we are aware of some situations like "Indeed, a Slack app's Request URL couldn't respond within 3 seconds but the main logic is successfully done on the server side. So, we don't want to repeat the logic again because running it again can result in duplicated outcomes (e.g., creating the same database record twice, posting the same message in a channel)". We call it a kind of workaround but as long as a developer does understand the downside of the approach, it can be okay in the real world.

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

No branches or pull requests

3 participants