即时通讯使用python 2.6,cherrypy 3.1
我的请求超时有问题。我只需要在Limit(30秒)内完成请求。在该限制之后,应该杀死进程并回答
服务器从tree.mount()开始; cherrypy.start(); cherrypy.block()
作为第一件事......当我试图杀死应用程序时(通过Ctrl + C(debian 6.0)),应用程序停留在:
等待子线程终止...
如何在退出时终止进程以及如何处理超时连接以杀死未响应的进程?
我不能在这里写任何代码,因为它是严格专有的,无论如何,我希望有人已经解决了这个问题。
问候马丁
答案 0 :(得分:3)
<强>注意即可。如果您在正常执行流程中不小心杀死线程或进程,那么很可能会搞砸。如果Python代码except
和finally
不能执行,您将遇到内存和同步问题(例如死锁),未关闭的文件句柄和套接字等等等等等等。 杀戮是解决您的问题的方法,就像断头台可能被称为治疗头皮屑一样。
一般来说,你不能这样做。没有这样的API。对于某些情况,您可以找到some hacks,但一般情况下您无法找到。{3}}。终止线程的唯一稳定方法是通过标志,事件等与之合作。
当您在拥有CherryPy Python进程的终端中按 Ctrl + C 时,解释器会收到SIGINT
信号并引发KeyboardInterrupt
异常。然后CherryPy命令其工作线程停止并告诉您等待子线程终止... 。如果在用户代码中阻止了工作线程,CherryPy将一直等到它被释放。
要强制停止,您可以使用常见的kill -9 PID
,其中PID
是您的CherryPy流程的进程ID。有时您可以使用任何过程监视器找到它。或者合并cherrypy.process.plugins.PIDFile
来编写流程的pid文件。
一般来说,CherryPy是一个线程服务器。如果您的任务有十几秒的响应,则很容易耗尽工作线程。在这种情况下,后台任务队列可能是一个好主意(Celery,Rq)或至少使用cherrypy.process.plugins.BackgroundTask
。但它显然会让您重新设计系统,进行临时结果存储,响应轮询或推送。它增加了复杂性,因此应该对所有利弊进行权衡。
如果您可以限制处理或计算的最终执行,那么您最好在那里执行。无论是数据库,还是Web服务API调用,或者其他什么,然后只处理超时异常。
CherryPy中的响应超时功能开箱即用。它由response.timeout
配置和cherrypy._TimeoutMonitor
控制,它在一个单独的线程中运行,并查看响应是否已超时。虽然实际上监视器只设置了一个属性response.timed_out
,稍后会在cherrypy._cprequest.Request.run
中查看该属性,如果它引发了真cherrypy.TimeoutError
。所以在事实后提出超时异常。如果您的页面处理程序阻塞了30秒,那么您将在30秒后获得异常。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import time
import cherrypy
config = {
'global' : {
'server.socket_host' : '127.0.0.1',
'server.socket_port' : 8080,
'server.thread_pool' : 8,
# interval in seconds at which the timeout monitor runs
'engine.timeout_monitor.frequency' : 1
},
'/' : {
# the number of seconds to allow responses to run
'response.timeout' : 2
}
}
class App:
@cherrypy.expose
def index(self):
time.sleep(8)
print('after sleep')
return '<em>Timeout test</em>'
if __name__ == '__main__':
cherrypy.quickstart(App(), '/', config)
你不能杀死一个线程,但你可以杀死一个进程。如果您无法以任何其他方式控制任务,则可以将执行包装在进程中并使用监视器在时间不足时将其终止。以下说明了这个想法。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import signal
import time
from multiprocessing import Process
import cherrypy
config = {
'global' : {
'server.socket_host' : '127.0.0.1',
'server.socket_port' : 8080,
'server.thread_pool' : 8,
# disable internal timeout monitor
'engine.timeout_monitor.on' : False,
# interval in seconds at which the timeout monitor runs
'engine.timeout_kill_monitor.frequency' : 1
},
'/' : {
# the number of seconds to allow responses to run
'response.timeout' : 2
}
}
class TimeoutKillMonitor(cherrypy._TimeoutMonitor):
def run(self):
cherrypy._TimeoutMonitor.run(self)
for request, response in self.servings:
if response.timed_out and hasattr(response, 'jobProcess'):
if response.jobProcess.is_alive():
os.kill(response.jobProcess.pid, signal.SIGKILL)
cherrypy.engine.timeout_kill_monitor = TimeoutKillMonitor(cherrypy.engine)
cherrypy.engine.timeout_kill_monitor.subscribe()
def externalJob():
time.sleep(8)
class App:
@cherrypy.expose
def index(self):
p = Process(target = externalJob)
p.start()
cherrypy.response.jobProcess = p
p.join()
# To determine whether your job process has been killed
# you can use ``killed = response.timed_out``. Reset it to
# ``False`` to avoid ``TimeoutError`` and response a failure
# state in other way.
return '<em>Result</em>'
if __name__ == '__main__':
cherrypy.quickstart(App(), '/', config)
请注意,您无法使用multiprocessing.Queue
或multiprocessing.Pipe
与您的工作进程进行通信,因为当它被杀死时,访问其中任何一个都会锁定您的CherryPy线程。以下是Process.terminate
的Python文档的引用。
如果关联进程使用管道或队列,则使用此方法,然后使用管道 或队列容易被破坏,并可能被其他进程无法使用。 类似地,如果进程已获得锁或信号量等,则终止它 可能导致其他进程陷入僵局。
所以是的,技术上可以强制超时,但这是一种沮丧和容易出错的方式。