我将首先解释我的系统架构,然后转到问题:
我有一个REST API,用作我的API网关。此服务器使用Flask构建。我也有RabbitMQ集群,我写的一个客户端可以监听特定队列并执行它所获得的任务。
到目前为止,我的所有请求都是异步的,因此一旦请求到达API网关,就会有一个callback_uri
字段,其中包含要将结果作为请求的一部分POST的URL,并且API网关是负责将任务发送到RabbitMQ并且工作人员处理了任务,最后将结果发回到回调URL。
我的问题是:
我希望新端点在某种意义上是同步的,处理将由与之前相同的工作者完成,但我想将结果返回到API网关以返回给用户并释放连接。
我目前的解决方案:
我像以前一样向工作人员发送一个唯一的callback_uri
作为请求的一部分,但现在特定的端点由我的API网关实现并允许POST和GET方法,因此工作人员可以POST结果一旦完成,我的API网关将继续轮询回调URL,直到结果可用,然后将结果返回给客户端。
除了忙于等待的HTTP工作人员轮询其自己的端点以获得结果之外,还有其他任何首选选项吗?但仍然是同步的,所以只有在结果可用时才释放连接?
仅供参考的代码:
@app.route('/long_task', methods=['POST'])
@sync_request
def long_task():
try:
if request.get_json() is None:
return ERROR_MSG_NO_JSON, 400
create_and_send_request_to_rabbitmq()
return '', 200
except Exception as ex:
return ERROR_MSG_NO_DATA, 400
def sync_request(func):
def call(*args, **kwargs):
create_callback_uri()
result = func(*args, **kwargs)
status_code = result[1]
if status_code == 200:
result = get_callback_result()
return result
return call
def get_callback_result():
callback_uri = request.get_json()['callback_uri']
has_answer = False
headers = {'content-type': 'application/json'}
empty_response = {}
content = json.dumps(empty_response)
try:
with Timeout(seconds=SYNC_REQUEST_TIMEOUT_SECONDS):
while not has_answer:
response = requests.get(callback_uri, headers=headers)
if response.status_code == 200:
has_answer = True
content = response.content
else:
time.sleep(0.2)
except TimeoutException:
log.debug('Timed out on sync request for request %s ' % request)
return content, 200
答案 0 :(得分:2)
因此,如果我理解正确,您希望您的后端等待某个工作人员的响应(通过RabbitMQ)。您可以通过实施rpc over rabbitmq来实现这一目标。关键的想法是使用相关ID。
但绝对最有效的方法是在websockets上运行客户端(如果它不是浏览器,则运行原始tcp套接字)并在作业完成时直接通知他。这样你就不会锁定资源(客户端连接,rabbitmq队列)而且你会避免性能损失(rpc)。