我正在使用 slack 命令(python 代码在此后面运行),它工作正常,但这会产生错误
This slash command experienced a problem: 'Timeout was reached' (error detail provided only to team owning command).
如何避免这种情况?
根据 Slack斜杠命令文档,您需要在 3000 毫秒(三秒)内响应。如果您的命令需要更长的时间,那么您会收到Timeout was reached
错误消息。您的代码显然不会停止运行,但用户不会得到任何对其命令的响应。
三秒钟对于您的命令可以即时访问数据的快速操作来说是可以的,但如果您正在调用外部 API 或执行一些复杂的操作,则可能不够长。如果您确实需要更长时间,请参阅文档的延迟响应和多重响应部分:
200
响应,可能类似于以下内容{'text': 'ok, got that'}
response_url
参数。POST
使用您的后续消息向该 URL 发出请求
:Content-type
需要是application/json
{'text': 'all done :)'}
根据文档,“您可以在用户调用后 30 分钟内最多响应用户命令 5 次”。
在我自己处理了这个问题并将我的 Flask 应用程序托管在 Heroku 上之后,我发现最简单的解决方案是使用线程。我按照这里的例子: 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
的Slack 消息的位置,并将其与任何其他可选数据一起传递给. 由于该过程现在被拆分,它几乎立即将消息返回到您的 Slack 频道,并在完成后发送第二条消息。receptionist()
response_url
backgroundworker()
"working on your request"
backgroundworker()
"your task is complete"
我也经常遇到这个错误:
“该死 - 斜杠命令不起作用(错误消息:)
Timeout was reached
。在 slash-command 管理命令”
我在 AWS Lambda 上编写了一个Slack 斜杠命令“机器人”,有时需要执行慢速操作(调用其他外部 API 等)。在某些情况下,Lambda 函数会花费超过 3 秒的时间,从而导致Timeout was reached
Slack 出错。
我在这里找到了@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
从上面可以看出,我没有直接从调度程序调用工作 Lambda 函数(尽管这是可能的)。我选择使用 AWS SNS 发布工作人员接收和处理的消息。
基于这个 StackOverflow 答案,这是更好的方法,因为它是非阻塞(异步)和可扩展的。此外,在 AWS Lambda 的上下文中使用 SNS 解耦这两个函数更容易,直接调用对于这个用例来说更棘手。
最后,这是我在工作人员 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`