Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/entity-framework/4.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 Twisted webapp在生成HTTP响应时卡住_Python_Twisted - Fatal编程技术网

Python Twisted webapp在生成HTTP响应时卡住

Python Twisted webapp在生成HTTP响应时卡住,python,twisted,Python,Twisted,我已经使用Twisted和SQLAlchemy创建了一个web应用程序。由于SQLAlchemy不能与Twisted基于回调的设计()很好地协同工作,因此我在根资源中使用deferToThread(),以便在其自己的线程中运行每个请求。虽然这通常是可行的,但大约10%的请求被“卡住”。这意味着,当我在浏览器中单击一个链接时,Twisted将处理请求,相应资源的代码将运行并生成HTML输出。但无论出于何种原因,该输出永远不会发送回浏览器。相反,Twisted发送HTTP头(以及正确的内容长度),但

我已经使用Twisted和SQLAlchemy创建了一个web应用程序。由于SQLAlchemy不能与Twisted基于回调的设计()很好地协同工作,因此我在根资源中使用
deferToThread()
,以便在其自己的线程中运行每个请求。虽然这通常是可行的,但大约10%的请求被“卡住”。这意味着,当我在浏览器中单击一个链接时,Twisted将处理请求,相应资源的代码将运行并生成HTML输出。但无论出于何种原因,该输出永远不会发送回浏览器。相反,Twisted发送HTTP头(以及正确的内容长度),但从不发送正文。通过浏览器显示微调器图标,连接将无限期保持打开状态。日志文件中的Twisted不会生成任何错误

下面是一个简单的例子。如果要运行它,请使用.tac扩展名保存它,然后运行
twistd-noy example.tac
。在我的服务器上,这个问题在这段特定代码中似乎比较少见。使用类似于
的东西,而不是true;做wget-O-'http://server.example.com:8080'>/dev/null;完成测试

from twisted.web.server import Site
from twisted.application import service, internet
from twisted.web.resource import Resource
from twisted.internet import threads
from twisted.web.server import NOT_DONE_YET
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine, Column, Integer, String

Base = declarative_base()
class User(Base):
    '''A user account.'''
    __tablename__ = 'user'
    id = Column(Integer, primary_key=True)
    login = Column(String(64))


class WebInterface(Resource):

    def __init__(self):
        Resource.__init__(self)
        db_url = "mysql://user:password@mysql-server.example.com/myapp?charset=utf8"
        db_engine = create_engine(db_url, echo=False, pool_recycle=300) #discard connections after 300 seconds
        self.DBSession = sessionmaker(bind=db_engine)

    def on_request_done(self, _, request):
        '''All actions that need to be done after a request has been successfully handled.'''
        request.db_session.close()
        print('Session closed') #does get printed, so session should get closed properly


    def on_request_failed(self, err, call):
        '''What happens if the request failed on a network level, for example because the user aborted the request'''
        call.cancel()


    def on_error(self, err, request):
        '''What happens if an exception occurs during processing of the request'''
        request.setResponseCode(500)
        self.on_request_done(None, request)
        request.finish()
        return err 


    def getChild(self, name, request):
        '''We dispatch all requests to ourselves in order to be able to do the processing in separate threads'''
        return self


    def render(self, request):
        '''Dispatch the real work to a thread'''
        d = threads.deferToThread(self.do_work, request)
        d.addCallbacks(self.on_request_done, errback=self.on_error, callbackArgs=[request], errbackArgs=[request])
        #If the client aborts the request, we need to cancel it to avoid error messages from twisted
        request.notifyFinish().addErrback(self.on_request_failed, d)
        return NOT_DONE_YET


    def do_work(self, request):
        '''This method runs in thread context.'''
        db_session = self.DBSession()
        request.db_session = db_session
        user = db_session.query(User).first()

        body = 'Hello, {} '.format(user.login) * 1024 #generate some output data
        request.write(body)
        request.finish()


application = service.Application("My Testapp")
s = internet.TCPServer(8080, Site(WebInterface()), interface='0.0.0.0')
s.setServiceParent(application)

您是否可能没有关闭数据库连接,或者使用SQLAlchemy时数据库中出现死锁情况?我曾经因为没有关闭连接/没有结束交易而被flask锁住。

我已经解决了这个问题@贝勒,你的猜测很接近。从我的问题的源代码中可以看出,DB会话在请求处理启动后打开,但两个会话以相同(而不是相反)的顺序关闭。在调用
request.finish()
之前关闭会话,一切正常。

此代码在语法上不正确(缩进错误),即使它是正确的,即使它具有所有必要的导入,也不会执行任何操作并退出。即使将其添加到资源树中,也会引发
获取正确的资源
并退出的
名称错误。有关如何制作一个有用示例的说明,请参阅。很可能您在错误的线程中调用了一些Twisted API。这种情况的症状通常是“某些数据有时会消失或需要很长时间才能显示”。但是没有一个sscce.org,很难说得更多。@Glyph:好的,我修正了压痕仍然不正确的问题;你真的测试过这个例子吗?唉。。。对不起,我在这里发帖时把代码缩进搞砸了。是的,我已经运行了代码。连接应该正确关闭,请参阅我添加的最小示例。是吗?即使有错误?即使出现错误,也应验证是否调用了on_request_done。因为它可能正在锁定您正在选择的表。您正在运行哪个数据库服务器。您可以在等待响应返回时重新启动数据库来检查这一点。