Saturday, 10 June 2017

Implementing Slack slash command delayed responses

I built a Slack slash command that communicates with a custom Node API and POSTS acronym data in some way, shape, or form. It either gets the meaning of an acronym or adds/removes a new acronym to a Mongo database.

The command works pretty well so far, but Slack occasionally returns a timeout error because it expects a response within 3 seconds. As a result, I'm trying to implement delayed responses. I'm not sure that I am implementing delayed responses properly for my Slack slash command & Node API.

This resource on Slack slash commands has information on delayed responses. The idea is that I want to send a 200 response immediately to let the Slack user know that their request has been processed. Then I want to send a delayed response to slackReq.response_url that isn't constrained by the 3-second time limit.

The Code

let jwt = require('jsonwebtoken');
let request = require('request');

let slackHelper = require('../helpers/slack');

// ====================
// Slack Request Body
// ====================

// {
//   "token":"~",
//   "team_id":"~"
//   "team_domain":"~",
//   "channel_id":"~",
//   "channel_name":"~",
//   "user_id":"~",
//   "user_name":"~",
//   "command":"~",
//   "text":"~",
//   "response_url":"~"
// }

exports.handle = (req, res) => {
  let slackReq = req.body;
  let token = slackReq.token;
  let teamId = slackReq.team_id;

  if (!token || !teamId || !slackHelper.match(token, teamId)) {
    // Handle an improper Slack request 
    res.json({
      response_type: 'ephemeral',
      text: 'Incorrect request'
    });
  } else {
    // Handle a valid Slack request
    slackHelper.handleReq(slackReq, (err, slackRes) => {
      if (err) {
        res.json({
          response_type: 'ephemeral',
          text: 'There was an error'
        });
      } else {
        // NOT WORKING - Immediately send a successful response
        res.json({
          response_type: 'ephemeral',
          text: 'Got it! Processing your acronym request...'
        })

        let options = {
          method: 'POST',
          uri: slackReq.response_url,
          body: slackRes,
          json: true
        };

        // Send a delayed response with the actual acronym data
        request(options, err => {
          if (err) console.log(err);
        });
      }
    });
  }
};

What's Happening Right Now

Say I want to find the meaning of acronym NBA. I go on Slack and shoot out the following:

/acronym NBA

I then hit the 3-second timeout error - Darn – that slash command didn't work (error message: Timeout was reached). Manage the command at slash-command.

I send a request a few more times (2 to 4 times), and then the API finally returns, all at once:

Got it! Processing your acronym request...

NBA means "National Basketball Association".

What I Want to Happen

I go on Slack and shoot out the following:

/acronym NBA

I immediately get the following:

Got it! Processing your acronym request...

Then, outside of the 3-second window, I get the following:

NBA means "National Basketball Association".

I never hit a timeout error.

Conclusion

What am I doing wrong here? For some reason, that res.json() with the processing message isn't immediately being sent back. What can I do to fix this?

Thank you in advance!



via Pramod Jacob

No comments:

Post a Comment