Slack sends "operation_timeout" when running a command, whether the command fails or succeeds

See original GitHub issue

Description

Describe your issue here.

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

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

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

  • I’ve read and understood the Contributing guidelines and have done my best effort to follow them.
  • I’ve read and agree to the Code of Conduct.
  • 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: tested on both 3.11.1, and 3.12.1

node version: 12

OS version(s): AWS Lambda function

Steps to reproduce:

  1. Add a command with app.command('/command', () => {...})
  2. run /command to execute chat.postMessage method for multiple users

Expected result:

All the messages (DMs) being sent to users in the channel that /command was run in.

Actual result:

  1. When testing DMs for a 10 user channel:

All the DMs are sent properly, but the user receives operation_timeout error message. This occurs even if ack() is sent in the beginning of the function, and occurs whether the processBeforeResponse flag is or is not set.

  1. When sending DMs to >100 users

Some users get a DM. Many users don’t get a message at all, even after much time has passed. The operation_timeout error appears as before.

Attachments:

Logs, screenshots, screencast, sample project, funny gif, etc.

Issue Analytics

  • State:closed
  • Created a year ago
  • Comments:13 (6 by maintainers)

github_iconTop GitHub Comments

1reaction
seratchcommented, Aug 15, 2022

@linjer Indeed, our documentation can be more detailed to mitigate FaaS users’ confusion. Thanks for the suggestions. Before working on that, let me quickly answer your questions here:

How processBeforeResponse actually impacts user code

When processBeforeResponse is true, as mentioned here, Bolt holds off immediately sending an HTTP response regardless of ack() method call timing. This would be beneficial to prevent your FaaS runtime from being forcibly terminated by its platform.

do we need to ack() at all?

Except Events API patterns (meaning app.event, app.message listeners), your app still needs to perform ack() method call in your listener.

Should we move ack() to the end? Why couldn’t I just move ack() to the end if my process takes < 3s, and do I even need this config in this case?

No, you don’t. When processBeforeResponse is false plus your listener always uses await for async function calls, this way can work as you expect, even on FaaS runtime.

Contrarily, when processBeforeResponse is true, the timing to call ack() method does not matter. Bolt does not send an ack response until the whole listener function execution completes. We believe that this behavior is more predictable for many developers and that’s why we generally recommend using processBeforeResponse: true option for FaaS use cases.

However, as long as you understand how it works, placing await ack() at the end plus disabling processBeforeResponse is totally fine.

What is the relation of unhandledRequestTimeoutMillis to the 3s limit mentioned in many of the threads about FaaS + processBeforeResponse? Is it actually not a hard 3s limit, i.e. the process just needs to complete before unhandledRequestTimeoutMillis which has a default value of 3000ms?

The only way to utilize unhandledRequestTimeoutMillis option would be to set a smaller time period than 3 seconds and customize the user-facing error message rather than the default timeout error by Slack clients. That being said, this is not always useful. For instance, when handing Events API payloads, telling the timeouts to end-users is not so simple. Your app may have to send a DM/channel message (meaning your app needs to call conversations.open, chat.postMessage API, and so on) to the affected user to inform that a timeout situation occurred due to your 3rd party app’s response time.

Can we also change the expected response timeout in the Slack app UI?

No, there is no way to adjust this as of today. Also, we don’t have anything to share for future enhancement so far.

How does AwsLambdaReceiver differ from ExpressReceiver and what does this mean for users of other providers? Does it simply set processBeforeResponse: true as a convenience?

AwsLambdaReceiver is an optimized receiver for AWS Lambda functions. The receiver consists of only necessary code for AWS Lambda functions. It is much simpler and smaller piece of code. Although we haven’t done any performance test with it, AwsLambdaReceiver may perform slightly better in terms of memory footprint and runtime performance. That being said, other built-in receivers run fast enough.

What is AWS specific?

You can easily generate an AWS Lambda compatible handler function from the receiver’s start method as below:

module.exports.handler = async (event, context, callback) => {
  const handler = await awsLambdaReceiver.start();
  return handler(event, context, callback);
}

Refer to https://slack.dev/bolt-js/deployments/aws-lambda for more details. This way should be much handier and more flexible than using ExpressReceiver along with Express app converter: @vendia/serverless-express.

Suggestions to offload heavy processes seem to leave developers who want to use say(…) or respond(…) with result information in the dark - can we somehow reliably pass these to other processes?

Good point. Unfortunately, there is simple way to restore those utility methods in a different AWS Lambda execution (offload processes in your words). If you invoke the offload function as an HTTP triggered function with the same set of request body and headers, you may be able to reuse Bolt’s foundational layer for offload functions.

I hope these answers were helpful to you and future readers!

1reaction
akshay-gadkaricommented, Aug 9, 2022

Some of the issues with timing were unrelated, and caused by the lambda function itself timing out, which was fixed by raising the limit in the config settings there.

The error message still shows up after moving the ack(), removing processBeforeResponse, with and without the unhandled request changes. The function is pretty slow, so I’ll try using asynchronous execution, separate functions for time consuming logic, or running it on EC2 instead.

I’ll update if I notice anything else, but thanks for your help so far!

Read more comments on GitHub >

github_iconTop Results From Across the Web

slack slash command work but send "failed with the error ...
Meanwhile, Slack expects 200 status within 3 seconds if it doesn't get any response then it will throw "operation timeout" error.
Read more >
failed with the error "operation_timeout" | Slack Community
I am using Slack Slash commands to send requests to my AWS Lambda python app by an AWS API Gateway. However, after sending...
Read more >
Enabling interactivity with Slash Commands - Slack API
Your app can do this simply by sending back an empty HTTP 200 response to the original request. If you don't do this,...
Read more >
How to NOT develop a Slack Bot - Medium
Avoiding potential pitfalls while developing a slack bot on AWS Lambda ... saw the following error message, while using slash commands.
Read more >
Workspaces — TACO 8.0 documentation - Docs - Scalr
If login is successful, Terraform will store the token in plain text in the following file for use ... Lastly, from the command...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found