18

I'm using the Slack API to get a link from a Slack workspace. It works except when a message is posted, it triggers more then once. Everytime. Here is the code I have:

exports.slack = (req , res) => {    
var message = req.body;

if (message.challenge) {
     res.send(message.challenge);

} else if (message.event.type == 'message_received') {
    if (message.event.text.includes('<')) {
        // Link
        console.log('NEW LINK');

        var link = message.event.text.slice(1, -1); 

        getArticleInfo(link, (error, body) => {
            if (error) 
                console.error(error);
            else {
                newArticleToDB(body , link, req);
            }
        });  
    }
  } 
}

Everytime a new message is posted I get a 'NEW LINK' log multiple times. Any ideas where to look for this issue?

Thanks.

olli208
  • 323
  • 2
  • 10
  • are there any event ids? maybe you could try to check if received event has different event than event before, like `if(message.event.id != lasteventid){ run even handler }`, by ID I mean some kind of number which changes or increases with each received event – bestestefan Jun 06 '18 at 08:34
  • @stetoc just checked and each message ID is different when one message is posted. So it still triggers multiple times. – olli208 Jun 06 '18 at 08:40
  • maybe the issue is in other part than what you posted as code here? maybe you add some handlers multiple times? have you checked it? – bestestefan Jun 06 '18 at 08:42
  • @stetoc Yeah i removed all the if statements and just console logged the 'message' and I still get multiple logs. – olli208 Jun 06 '18 at 08:45
  • Try terminating the requests in the last two `else if` blocks with `res.json()`. As of now you're leaving the client hanging since you never send a response back. – Cisco Jun 06 '18 at 11:32
  • @FranciscoMateo What do you mean exactly? I don't necessarily want to send something back to Slack. I want to get the message from Slack and do my own thing with it and store it in my database. The problem is that it does that multiple times per one message, so if I want to do an API request for example to another service it does it multiple times also. – olli208 Jun 06 '18 at 12:16
  • 5
    If you don't acknowledge the request with some kind of HTTP 200 OK, then Slack thinks you didn't receives it and retries the request a few times. See https://api.slack.com/events-api#graceful_retries – Taylor Singletary Jun 06 '18 at 16:58
  • Slack send a second event as a retry. Responding with HTTP 200 worked for me –  Jan 18 '21 at 05:21
  • 2
    We need an updated answer with the bolt SDK- am seeing this same behavior. My understanding is that the bolt SDK is supposed to handle the ack in listeners but it isnt and ack() isnt a valid function to use in listeners. – Moriarty Aug 24 '22 at 15:39
  • also note in the section about graceful retries that you must respond with the 200 *within 3 seconds* otherwise it will retry – Andy Oct 06 '22 at 17:54

4 Answers4

13

I added res.sendStatus(200) and now everything works as expected. Here's the code:

exports.slack = (req , res) => {    
var message = req.body;
res.sendStatus(200);

if (message.challenge) {
    res.send(message.challenge);

} else if (message.event.type == 'message' && message.event.subtype != 'message_changed') {
    if (message.event.text && message.event.text.includes('<')) {
        // Link
        console.log('NEW LINK');

        var link = message.event.text.slice(1, -1); 

        getArticleInfo(link, (error, body) => {
            if (error) 
                console.error(error);
            else {
                newArticleToDB(body , link, req);
            }
        });  
    }
}
olli208
  • 323
  • 2
  • 10
8

I had the issue, thank for @taylor-singletary suggestion. I had to print

console.log('Request Headers::: ', JSON.stringify(req.headers));

to look for

"x-slack-retry-num":"1"

To get header value, simply refer to this question: How to extract request http headers from a request using NodeJS connect

vanduc1102
  • 5,769
  • 1
  • 46
  • 43
2

I had the same issue receiving multiple events. Turned out I was receiving 1 event per bot user event I added. I don't know if this is the API's intended behavior, but I decided to remove all events except app_mention and now I only receive 1 event.

Subscribe to bot events

Bobby T.
  • 78
  • 1
  • 7
0

Responding to events

Your app should respond to the event request with an HTTP 2xx within three seconds. If it does not, we'll consider the event delivery attempt failed. After a failure, we'll retry three times, backing off exponentially. Some best practices are to:

  1. maintain a response success rate of at least 5% of events per 60 minutes to prevent automatic disabling.

  2. respond to events with a HTTP 200 OK as soon as you can.

  3. avoid actually processing and reacting to events within the same process.

  4. implement a queue to handle inbound events after they are received.

What you do with events depends on what your application or service does.

Maybe it'll trigger you to send a message using chat.postMessage. Maybe you'll update a leaderboard. Maybe you'll update a piece of data you're storing. Maybe you'll change the world or just decide to do nothing at all.

Refer: https://api.slack.com/apis/connections/events-api#graceful_retries

Harshad Panmand
  • 410
  • 5
  • 19