我有一个Django应用程序的Web应用程序,我想知道是否有可能有nginx传播中止/closuresuwsgi / Django。
基本上我知道nginx知道过早的中止/closures,因为它默认为uwsgi_ignore_client_abort
“closures”,并且当发送响应之前请求被中止/closures时,你的nginx日志中会出现nginx 499错误。 一旦uwsgi完成处理请求,它会在返回响应给nginx的时候抛出一个“IO Error”。
将uwsgi_ignore_client_abort
为“on”只是让nginx不知道中止/closures,并删除uwsgi“IO Errors”,因为uwsgi仍然可以写回nginx。
我的用例是我有一个应用程序,人们快速浏览一些ajax结果,所以如果通过快速页面中止他们跳过页面的挂起的ajax请求,这将保持客户端清洁和高效。 但是这对服务器端(uwsgi / Django)没有任何作用,因为即使没有任何东西会等待响应,他们仍然需要处理每一个请求。
现在显然可能有某些页面,我不希望请求被任何原因提前中止。 但是,我使用芹菜长期运行的请求,可能属于这一类。
那么这可能吗? uwsgi uwsgi's
hariakari设置让我觉得它在某种程度上……只是不知道该怎么做。
我的用例是我有一个应用程序,人们快速浏览一些ajax结果,所以如果通过快速页面中止他们跳过页面的挂起的ajax请求,这将保持客户端清洁和高效。
在客户端中止AJAX请求是通过XMLHttpRequest.abort()
。 如果请求在调用abort()
时尚未发出,则请求不会出去。 但是,如果请求已经发送, 服务器将不知道请求已被中止。 连接不会关闭,不会有任何消息发送到服务器,什么都不是。 如果您希望服务器知道不再需要某个请求,则基本上需要提供一种识别请求的方法,以便在发出初始请求时获得该请求的标识符。 然后,通过另一个AJAX请求,你可以告诉服务器一个更早的请求应该被取消。 (如果你搜索这个关于abort()
问题,并搜索“server”,你会发现解释说相同。)
请注意, uwsgi_ignore_client_abort
是处理TCP级别的连接关闭的东西。 这与放弃AJAX请求是不同的。 在JavaScript中通常不会采取任何行动,这将导致关闭TCP连接。 浏览器根据需要优化连接的创建和销毁。 刚才我做了这个:
我使用lsof
来检查是否有任何进程与example.com
有连接。 没有。 ( lsof
是允许列出打开文件的* nix工具,网络连接是* nix中的“文件”)。
我在Chrome中打开了一个页面到example.com。 lsof
显示连接和打开它的过程。
然后我关闭了页面。
我用lsof
进行了调查,看我之前确定的连接是否仍然打开。 在关闭页面后,它保持打开状态大约一分钟,即使没有真正需要保持连接打开。
而且没有太多的uswgi设置的摆弄,这将使它意识到通过XMLHttpRequest.abort()
您提供的用例场景是用户通过一些结果快速分页的场景。 我可以看到两个可能性的问题给出的描述:
用户在进一步分页之前等待刷新。 例如,Alice正在浏览按用户名“Zeno”按字母顺序排列的用户名列表,每次显示一个新页面时,她都会看到该名称不存在,并且页面向下。 在这种情况下,没有什么可以放弃的,因为用户的行为取决于首先处理的请求。 (用户在作出决定之前必须看到新的页面。)
用户只是在不等待刷新的情况下下楼。 爱丽丝再次寻找“芝诺”,但她认为这将是在最后一页,所以点击,点击,她点击。 在这种情况下, 您可以删除对服务器发出的请求。 然后按下一页按钮,递增应该向用户显示的页面的数量,但不立即发送请求。 相反,在用户停止点击按钮之后等待一小段时间,然后用最终的页码发送请求,所以你发出一个请求,而不是一打。 这里是一个DataTables搜索执行去抖动的例子。
现在显然可能有某些页面,我不希望请求被任何原因提前中止。
这正是采取这种或那种方式背后的问题。
显然,你可能不想继续花费系统资源来处理已经中止的连接,例如昂贵的搜索操作。
但是,也许连接是非常重要的,即使客户端已经断开连接仍然需要处理。
例如,非常昂贵的搜索操作,但实际上不是客户端特定的,并且将由nginx为所有后续客户端缓存。
或者也许是一个修改你的应用程序状态的操作 – 你显然不希望你的应用程序有一个不一致的状态!
如上所述,问题出在uWSGI上,而不是在NGINX上。 但是,你不能让uWSGI自动决定你的意图,没有你自己向uWSGI透露这样的意图。
你将如何在代码中揭示你的意图? 一大堆编程语言并不真正支持多线程和/或异步编程模型,这使得取消操作变得完全不重要。
因此,这里没有魔术解决方案。 即使像Golang这样的并发编程语言在WithCancel
context
也有问题 – 你可能必须在每一个可能阻塞的函数调用中传递它,使得代码变得非常难看。
您是否已经在Django中传递上述上下文? 如果没有,那么这个解决方案是丑陋的,但很简单 – 任何时候你都可以明确地中止请求,检查客户端是否仍然与uwsgi.is_connected(uwsgi.connection_fd())
: