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"消息返回到松弛通道,完成后backgroundworker()发送第二条消息"your task is complete"。
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
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`
根据松弛度slash command documentation,您需要在3000毫秒(3秒)内做出响应。如果您的命令需要更长时间,则会出现
Timeout was reached
错误。显然,您的代码不会停止运行,但用户不会得到对其命令的任何响应。对于命令可以即时访问数据的快速操作来说,3秒是很好的,但是如果调用外部api或执行复杂的操作,3秒可能不够长。如果您需要更长的时间,请参阅文档中的延迟响应和多个响应部分:
200
响应,可能是{'text': 'ok, got that'}
行中的内容response_url
参数。使用后续消息向该URL发出POST
请求:Content-type
需要application/json
{'text': 'all done :)'}
根据这些文档,“在用户调用后的30分钟内,您最多可以对用户命令做出5次响应”。
在我自己解决了这个问题,并将Flask应用程序托管在Heroku上之后,我发现最简单的解决方案是使用线程。我从这里举了个例子: https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-xi-email-support
所有缓慢而繁重的工作都由
backgroundworker()
函数执行。slack命令指向https://myappaddress.com/appmethodaddress
,其中receptionist()
函数接受接收到的slack消息的response_url
,并将其与任何其他可选数据一起传递给backgroundworker()
。当进程现在被拆分时,它只需立即将"working on your request"
消息返回到松弛通道,完成后backgroundworker()
发送第二条消息"your task is complete"
。我也经常面临这个错误:
我正在写一个Slack slash-command "bot" on AWS Lambda,有时需要执行缓慢的操作(调用其他外部api等)。在某些情况下,Lambda函数需要3秒以上的时间,这会导致Slack产生
Timeout was reached
错误。我在这里找到了@rcoup的优秀答案,并将其应用到AWS Lambda的上下文中。错误不再出现。
我是用两个独立的Lambda函数来实现的。一个是“dispatcher”或“receptor”,它用“200ok”来迎接输入的Slack slash命令,并向用户返回简单的“OK,got that”类型的消息。另一个是实际的“worker”Lambda函数,它异步启动长ish操作,并在稍后将该操作的结果发布到Slack
response_url
。这是调度员/接待员Lambda函数:
从上面可以看到,我没有直接从调度程序调用worker Lambda函数(尽管这是可能的)。我选择了use AWS SNS to publish a message that the worker receives and processes。
基于this StackOverflow answer,这是更好的方法,因为它是无阻塞(异步)和可伸缩的。另外,在AWS Lambda上下文中使用SNS来分离这两个函数也更容易,直接调用对于这个用例来说更为棘手。
最后,我将在worker Lambda函数中使用SNS事件:
相关问题 更多 >
编程相关推荐