bolt-python icon indicating copy to clipboard operation
bolt-python copied to clipboard

slack is posting two/three messages with chat_postMessage

Open kunalrc2022 opened this issue 1 year ago • 9 comments

Description

Describe your issue here. I am using slack-bolt python framework for my slack bolt which is going through some logic. I am using chat_postMessage method to send a message from bot. But currently it is sending three messages even though it's having single API call. I read about it and notices that it can be avoided with making X-Slack-Retry-Num =1 in header.(https://api.slack.com/apis/connections/events-api#graceful_retries) But i am wondering how can i change the header of the api call in res_out = app.client.chat_postMessage(channel=message['channel'],thread_ts = original_thread_id,blocks=block_final)

What type of issue is this? (place an x in one of the [ ])

  • [ ] bug
  • [ ] enhancement (feature request)
  • [ ] question
  • [ ] documentation related
  • [x] example code related
  • [ ] testing related
  • [ ] discussion

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

  • [x ] I've read and understood the Contributing guidelines and have done my best effort to follow them.
  • [x] I've read and agree to the Code of Conduct.
  • [x] I've searched for any related issues and avoided creating a duplicate issue.

Bug Report

Filling out the following details about bugs will help us solve your issue sooner.

Reproducible in:

package version:

node version:

OS version(s):

Steps to reproduce:

  1. use res_out = app.client.chat_postMessage(channel=message['channel'],thread_ts = original_thread_id,blocks=block_final) in the bot's code and due to retry mechanism it tries and sends the same message thrice on single call.

Expected result:

Bot should only post single message.

Actual result:

Bot is posting two/three same messages

Attachments:

kunalrc2022 avatar Aug 03 '22 19:08 kunalrc2022

Transferring this issue to slackapi/bolt-python

mwbrooks avatar Aug 03 '22 19:08 mwbrooks

Hi @kunalrc2022 👋🏻 Thanks for reaching out!

I've transferred this issue to slackapi/bolt-python because it looks like you're using the Python framework instead of the JavaScript framework.

Can you provide a complete code example of posting a message into Slack? Thanks for the steps to reproduce, but I think it will be helpful to understand when you're posting a message. For example, are you responding to an event or action? Some requests must be acknowledged and the Slack API will re-send the request multiple times when it's not acknowledge. This could be one reason why you're sending multiple messages.

mwbrooks avatar Aug 03 '22 19:08 mwbrooks

hey @mwbrooks thanks for looking into it. I am using it in response to app.message event. Please refer below eg i am using in the code.

@app.message(re.compile("(TECHAWAY-)"))
def message_hello(message, ack,say):
  ack()
  ''' 
  Having code logic and if else checks
  ""
  res_out = app.client.chat_postMessage(channel=message['channel'],thread_ts = original_thread_id,blocks=block_final)

kunalrc2022 avatar Aug 03 '22 20:08 kunalrc2022

Is there a way i can limit it's retry attempt count to 1 in the the above api call ?

kunalrc2022 avatar Aug 03 '22 20:08 kunalrc2022

hello @mwbrooks /team team, could anybody please help me with the above message ?

kunalrc2022 avatar Aug 04 '22 12:08 kunalrc2022

Hello @mwbrooks , @objectfox @episod @seratch hope you are doing well. Could you please have a look at the above issue and help me to resolve it ?

kunalrc2022 avatar Aug 05 '22 13:08 kunalrc2022

@kunalrc2022 have you tried putting something into app.client.headers? Like app.client.headers['X-Slack-Retry-Num'] = 1 before the chat_postMessage call?

objectfox avatar Aug 05 '22 15:08 objectfox

Hello @objectfox , thanks for looking into this request . i have tried adding app.client.headers['X-Slack-Retry-Num'] = 1 before using chat_postMessage but still sometimes it sends multiple messages.

Here is the piece of lines i am using in the code: app.client.headers['X-Slack-Retry-Num'] = 1 res_out = app.client.chat_postMessage(channel=message['channel'],thread_ts = original_thread_id,blocks=block_final)

kunalrc2022 avatar Aug 05 '22 19:08 kunalrc2022

@kunalrc2022

Is there a way i can limit it's retry attempt count to 1 in the the above api call ?

If your Bolt app cannot respond to message events within 3 seconds for some reason, the Slack server-side can send retry requests up to 3 times. There is no way to prevent this behavior but you can check X-Slack-Retry-Num (retry_attempt in Socket Mode) value. To do this, you can use request argument in a global middleware:

@app.use # or @app.middleware
def ignore_retry_request(request, ack, next):
    if _is_retry(request):  # implement this predicate function on your own
        return ack()
    next()  # if this is not a retry, Bolt app should handle it

See also:

  • https://slack.dev/bolt-python/api-docs/slack_bolt/kwargs_injection/args.html#slack_bolt.kwargs_injection.args.Args.request
  • https://slack.dev/bolt-python/api-docs/slack_bolt/request/request.html#slack_bolt.request.request.BoltRequest
  • https://slack.dev/bolt-python/concepts#global-middleware

I think I've answered your question here. Would you mind closing this issue now?

seratch avatar Aug 05 '22 21:08 seratch

Since we've already provided answers to the question here, let us close this issue now. That said, if you have anything further to discuss here, please don't hesitate to write in more 👋

seratch avatar Aug 15 '22 05:08 seratch

Hello @seratch,Thank you for the detailed explanation. May I ask how this code is implemented?

 if _is_retry(request):  # implement this predicate function on your own

iwakiri0104 avatar Oct 04 '22 04:10 iwakiri0104

Hi @iwakiri0104, the request object has headers property. You can extract any values from it: https://slack.dev/bolt-python/api-docs/slack_bolt/request/request.html#slack_bolt.request.request.BoltRequest.headers

seratch avatar Oct 04 '22 04:10 seratch

Hello @seratch,Thank you for answering! But sorry, I have no idea how to use this information to implement the code. Do I need to write all the class BoltRequest: statements?

iwakiri0104 avatar Oct 04 '22 05:10 iwakiri0104

@iwakiri0104 No, the request object is already an instance of the class. You can access the properties listed in the module document. More specifically, you should be able to check the existence of retry-related headers in request.headers.

seratch avatar Oct 04 '22 05:10 seratch

@seratch Thanks for the detailed explanation. I tried to check the log with this code, but I can't see the contents. Thank you

Is the extraction not working with this code?

def _is_retry(request):
    logging.info("request is:",json.dumps(request))
    logging.info("request headers is:",json.dumps(request.headers))
    if "X-Slack-Retry-Num" in request.headers:
        return True

iwakiri0104 avatar Oct 04 '22 05:10 iwakiri0104

@iwakiri0104 This issue is already closed. I will reply to your issue #731

seratch avatar Oct 04 '22 06:10 seratch