Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/349.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 当新请求来自同一会话中的同一用户时,如何取消以前的请求_Python_Http_Nginx_Python Asyncio_Aiohttp - Fatal编程技术网

Python 当新请求来自同一会话中的同一用户时,如何取消以前的请求

Python 当新请求来自同一会话中的同一用户时,如何取消以前的请求,python,http,nginx,python-asyncio,aiohttp,Python,Http,Nginx,Python Asyncio,Aiohttp,我们正在使用aiohttp构建一个restapi。我们的应用程序设计为用户发送请求的频率高于接收响应的频率(因为计算时间)。对于用户而言,仅最新请求的结果很重要。是否可以停止对过期请求的计算 谢谢你你正在构建一个非常不像HTTP的东西。HTTP请求的响应时间不应超过几毫秒,并且HTTP请求不应相互依赖;如果您需要执行耗时较长的计算,请尝试通过更改体系结构/模型/缓存/任何内容来加快计算速度,或者明确地将其视为可通过HTTP接口控制的长时间运行作业。这意味着“作业”是可通过HTTP查询的“物理资源

我们正在使用aiohttp构建一个restapi。我们的应用程序设计为用户发送请求的频率高于接收响应的频率(因为计算时间)。对于用户而言,仅最新请求的结果很重要。是否可以停止对过期请求的计算


谢谢你

你正在构建一个非常不像HTTP的东西。HTTP请求的响应时间不应超过几毫秒,并且HTTP请求不应相互依赖;如果您需要执行耗时较长的计算,请尝试通过更改体系结构/模型/缓存/任何内容来加快计算速度,或者明确地将其视为可通过HTTP接口控制的长时间运行作业。这意味着“作业”是可通过HTTP查询的“物理资源”。您可以通过POST请求创建资源:

POST /tasks
Content-Type: application/json

{"some": "parameters", "go": "here"}
然后可以查询任务的状态:

GET /tasks/42
GET /tasks/42
并最终取得成果:

当你发布一个新任务取代旧任务时,你的后端可以用任何它认为合适的方式取消旧任务;然后,资源将返回“已取消”或类似的状态。您的客户机在启动新任务后不会再次查询旧资源


即使您的客户端每秒查询一次资源,它仍然会使用较少的服务器资源(一个连接持续打开10秒,而在同一时间段内10个连接持续打开200毫秒),特别是如果您对其应用了一些智能缓存。这也更具可扩展性,因为您可以独立于HTTP前端将任务后端扩展到它,并且HTTP前端可以轻松地扩展到多个服务器和负载平衡器。

我将发布@Drizzt1991的解决方案:

嘿,阿泰姆。你有一个很奇怪的要求。 请理解,如果一个客户机正在使用带有keep-alive的套接字,那么在回答第一个请求之前,实际上不可能看到下一个请求。这就是HTTP的工作方式,它在发送另一个请求之前需要一个结果。 所以,只有当客户机在两个单独的套接字上运行时,您的案例才会起作用,但您需要再次声明,来自同一客户机的两个套接字将路由到同一台机器上。实际上,这对于故障转移之类的东西并不是很好。基本上,它将是一个有状态的API。 即使您做了所有这些,也不是所有库都支持取消。传统的关系数据库只会忽略结果,但仍会处理挂起的查询。如果你做一些复杂的事情,比如图遍历,并且你有很多步骤,这是可以取消的

但是,如果您断言,客户端使用一个套接字池,它们被路由到同一台机器,请求将从取消中受益,类似这样的操作应该可以做到:


这违反了HTTP的核心原则之一。如果您想将该服务扩展到负载平衡器后面的多个服务器,该怎么办;然后,取消其他服务器可能正在处理的请求会变得非常棘手。这可能不是您应该尝试解决的实际问题!“取消”到底是什么意思?服务器会断开连接?重写后:这是否意味着一个HTTP请求可能需要几分钟(?)才能完成?这也是糟糕的HTTP设计;一个请求最多应在几秒钟内得到响应,典型的基线目标为200ms。如果需要更长时间运行的作业,请将其视为作业:一个HTTP请求启动后台任务并返回任务id。然后,客户端可以使用另一个HTTP请求查询作业状态。例如,
POST/tasks{params}
GET/tasks/42
。显然,这样的后台任务可以通过任何在后端有意义的机制取消。我们现在的目标是5-10秒。对于HTTP请求来说太长了。根据
POST/tasks
接受新的“作业请求”,启动独立于web服务器的后台任务,返回新的资源id。让客户端查询新资源的结果/状态(
GET/tasks/42
)。如果有新任务取代该任务,则取消该任务;客户端可以意识到这种隐式取消,不再需要查询旧资源。
{"status": "pending"}
GET /tasks/42
{"status": "done", "results": [...]}
import asyncio
import random

from aiohttp import web


def get_session_id(request):
    # I don't know how you do session management, so left it out
    return ""


async def handle(request):
    session_id = get_session_id(request)
    request['tr_id'] = tr_id = int(random.random() * 1000000)

    running_tasks = request.app['running_tasks']
    if session_id in running_tasks and not running_tasks[session_id].done():
        running_tasks[session_id].cancel()
        del running_tasks[session_id]

    current_task = asyncio.ensure_future(_handle_impl(request))
    running_tasks[session_id] = current_task

    try:
        resp = await current_task
    except asyncio.CancelledError:
        print("Cancelled request", tr_id)
        resp = web.Response(text="Cancelled {}".format(tr_id))
    finally:
        if running_tasks[session_id] is current_task:
            del running_tasks[session_id]
    return resp


async def _handle_impl(request):
    tr_id = request['tr_id']
    print("Start request", tr_id)
    await asyncio.sleep(10)
    print("Finished request", tr_id)
    return web.Response(text="Finished {}".format(tr_id))


app = web.Application()
app.router.add_get('/', handle)
app.router.add_get('/{name}', handle)

app['running_tasks'] = {}

web.run_app(app, host="127.0.0.1", port=8080)