我正在使用slack命令(python代码在此后面运行),它工作正常,但这会给出错误
This slash command experienced a problem: 'Timeout was reached' (error detail provided only to team owning command).
如何避免这种情况?
答案 0 :(得分:34)
根据Slack slash command documentation,您需要在3000毫秒(3秒)内响应。如果您的命令需要更长时间,则会出现Timeout was reached
错误。您的代码显然不会停止运行,但用户无法获得对其命令的任何响应。
对于您的命令可以即时访问数据的快速事情,可以使用三秒钟,但如果您要调用外部API或执行复杂操作,则可能不够长。如果您做需要更长时间,请参阅文档中的延迟响应和多个响应部分:
200
响应,可能与{'text': 'ok, got that'}
response_url
参数。使用您的后续消息向该网址发出POST
个请求:
Content-type
需要application/json
{'text': 'all done :)'}
根据文档,"您可以在用户调用的30分钟内响应用户命令最多5次。
答案 1 :(得分:8)
我也经常遇到这个错误:
“Darn - 斜杠命令不起作用(错误消息:
Timeout was reached
)。在slash-command管理命令”
我正在编写Slack slash-command "bot" on AWS Lambda,有时需要执行慢速操作(调用其他外部API等)。在某些情况下,Lambda函数需要大于3秒才会导致Slack出现Timeout was reached
错误。
我在这里找到了@ rcoup的优秀答案,并将其应用于AWS Lambda的上下文中。该错误不再出现。
我用两个独立的Lambda函数做到了这一点。一个是“调度员”或“接待员”,它用“200 OK”迎接传入的Slack斜杠命令,并向用户返回简单的“Ok,got that”类型的消息。另一个是实际的“worker”Lambda函数,它以异步方式启动long-ish操作,并在稍后将该操作的结果发布到Slack response_url
。
这是调度员/接待员Lambda函数:
def lambda_handler(event, context):
req_body = event['body']
try:
retval = {}
# the param_map contains the 'response_url' that the worker will need to post back to later
param_map = _formparams_to_dict(req_body)
# command_list is a sequence of strings in the slash command such as "slashcommand weather pune"
command_list = param_map['text'].split('+')
# publish SNS message to delegate the actual work to worker lambda function
message = {
"param_map": param_map,
"command_list": command_list
}
sns_response = sns_client.publish(
TopicArn=MY_SNS_TOPIC_ARN,
Message=json.dumps({'default': json.dumps(message)}),
MessageStructure='json'
)
retval['text'] = "Ok, working on your slash command ..."
except Exception as e:
retval['text'] = '[ERROR] {}'.format(str(e))
return retval
def _formparams_to_dict(req_body):
""" Converts the incoming form_params from Slack into a dictionary. """
retval = {}
for val in req_body.split('&'):
k, v = val.split('=')
retval[k] = v
return retval
从上面可以看出,我没有直接从调度程序调用worker Lambda Function(虽然这是可能的)。我选择了use AWS SNS to publish a message that the worker receives and processes。
基于this StackOverflow answer,这是更好的方法,因为它是非阻塞(异步)和可扩展的。此外,使用SNS在AWS Lambda的上下文中解耦这两个函数也更容易,直接调用对于这个用例来说更为棘手。
最后,这是我在工作人员Lambda函数中使用SNS事件的方法:
def lambda_handler(event, context):
message = json.loads(event['Records'][0]['Sns']['Message'])
param_map = message['param_map']
response_url = param_map['response_url']
command_list = message['command_list']
main_command = command_list[0].lower()
# process the command as you need to and finally post results to `response_url`
答案 2 :(得分:7)
在我自己处理这个问题并在Heroku上托管我的Flask应用程序后,我发现最简单的解决方案是使用线程。我按照这里的例子: https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-xi-email-support
from threading import Thread
def backgroundworker(somedata,response_url):
# your task
payload = {"text":"your task is complete",
"username": "bot"}
requests.post(response_url,data=json.dumps(payload))
@app.route('/appmethodaddress',methods=['POST','GET'])
def receptionist():
response_url = request.form.get("response_url")
somedata = {}
thr = Thread(target=backgroundworker, args=[somedata,response_url])
thr.start()
return jsonify(message= "working on your request")
所有缓慢繁重的工作都由backgroundworker()
功能执行。我的slack命令指向https://myappaddress.com/appmethodaddress
,其中receptionist()
函数接收收到的Slack消息的response_url
,并将其与任何其他可选数据一起传递给backgroundworker()
。由于流程现在已拆分,因此只需立即将"working on your request"
消息返回到Slack通道,完成后backgroundworker()
会发送第二条消息"your task is complete"
。
答案 3 :(得分:-12)
创建线程来完成大部分工作并将响应返回到slack。您还可以在线程完成时返回响应。