2

我正在使用 Twisted 开发一个 Web 服务,该服务负责调用我以前在命令行上使用过的几个包。这些包处理的例程是自己制作的原型,但现在可以集成到我们的 Web 服务中。

简而言之,我有几个不同的模块,它们都以原始命令行形式在内部创建了一个 mysql 连接属性。以此为例:

class searcher:
  def __init__(self,lat,lon,radius):
    self.conn = getConnection()[1]
    self.con=self.conn.cursor();

    self.mgo = getConnection(True)

    self.lat = lat
    self.lon = lon
    self.radius = radius
    self.profsinrange()
    self.cache = memcache.Client(["173.220.194.84:11211"])

getConnection 函数只是一个帮助器,分别返回一个 mongo 或 mysql 游标。同样,这都是原型:)

我遇到的问题是,当使用 Twisted 的 WSGI 资源作为持续运行的服务器实现时,init 中创建的 sql 连接超时,并且后续请求似乎没有重新生成它。小型服务器应用程序的示例代码:

from twisted.web import server
from twisted.web.wsgi import WSGIResource
from twisted.python.threadpool import ThreadPool
from twisted.internet import reactor
from twisted.application import service, strports
import cgi

import gnengine
import nn

wsgiThreadPool = ThreadPool()
wsgiThreadPool.start()

# ensuring that it will be stopped when the reactor shuts down
reactor.addSystemEventTrigger('after', 'shutdown', wsgiThreadPool.stop)


def application(environ, start_response):
    start_response('200 OK', [('Content-type','text/plain')])
    params = cgi.parse_qs(environ['QUERY_STRING'])
    try:
      lat =  float(params['lat'][0])
      lon = float(params['lon'][0])
      radius = int(params['radius'][0])
      query_terms = params['query']
      s = gnengine.searcher(lat,lon,radius)
      query_terms = ' '.join( query_terms )
      json = s.query(query_terms)
      return [json]
    except Exception, e:
      return [str(e),str(params)]

    return ['error']

wsgiAppAsResource = WSGIResource(reactor, wsgiThreadPool, application)

# Hooks for twistd
application = service.Application('Twisted.web.wsgi Hello World Example')
server = strports.service('tcp:8080', server.Site(wsgiAppAsResource))
server.setServiceParent(application)

前几个请求工作正常,但在 mysqlswait_timeout过期后,可怕的错误 2006 “Mysql has gone away” 错误浮出水面。我的理解是,对 WSGI Twisted 资源的每个请求都会运行应用程序功能,从而重新生成搜索器对象并重新租用连接。如果不是这种情况,我该如何处理请求?这种 Twisted 部署在这个意义上不是事务性的吗?谢谢!

编辑:根据请求,这里是调用连接的原型辅助函数:

def getConnection(mong = False):
    if mong == False:
    connection = mysql.connect(host = db_host,
                   user = db_user,
                   passwd = db_pass,
                   db = db,
                   cursorclass=mysql.cursors.DictCursor)
    cur = connection.cursor();
    return (cur,connection)
    else:
    return pymongo.Connection('173.220.194.84',27017).gonation_test
4

1 回答 1

2

我正在开发一个扭曲的软件,我必须使用一个恒定的 MySQL 数据库连接。我确实遇到了这个问题,并深入研究了扭曲的文档并发布了一些我无法找到合适的解决方案的问题。当你实例化 adbapi.connectionPool 类时,你可以传递一个布尔参数;然而,它似乎从来没有工作过,我一直得到错误不管。但是,我猜测重新连接布尔值表示的是当 SQL 断开连接确实发生时连接对象的破坏。

adbapi.ConnectionPool("MySQLdb", cp_reconnect=True, host="", user="", passwd="", db="")

我没有对此进行测试,但我会在测试时重新发布一些结果,或者如果其他人有请分享。

当我开发脚本时,我使用的是twisted 8.2.0(我有一段时间没有接触过twisted),当时框架没有这种明确的保持活动状态,所以我开发了一个ping/keepalive扩展,使用事件驱动的范例twisted构建结合直接 MySQLdb 模块 ping() 方法(参见代码注释)。当我输入这个回复时;但是,我确实查看了当前扭曲的文档,但我仍然无法找到明确的保持活动方法或参数。我的猜测是因为 twisted 本身没有数据库连接库/类。它使用 python 可用的方法并提供与这些模块的间接接口层;直接调用正在使用的数据库库有一些曝光。这是通过使用 adbapi.runWithConnection 方法完成的。

这是我在 twisted 8.2.0 和 python 2.6 下编写的模块;您可以设置 ping 之间的间隔。该脚本的作用是,每 20 分钟对数据库执行一次 ping 操作,如果失败,则每 60 秒尝试重新连接一次。我必须警告该脚本不处理突然/断开的连接;每当您通过扭曲运行查询时,您都可以通过 addErrback 处理,至少我就是这样做的。我注意到,每当数据库连接断开时,您只能在执行查询并且事件引发 errback 时确定它是否存在,然后在此时处理它。基本上,如果我在 10 分钟内不运行查询,并且我的数据库断开了我的连接,我的应用程序将不会实时响应。应用程序将在运行随后的查询时意识到连接已断开;



from twisted.enterprise import adbapi
from twisted.internet import reactor, defer, task

class sqlClass:
        def __init__(self, db_pointer):
                self.dbpool=db_pointer
                self.dbping = task.LoopingCall(self.dbping)
                self.dbping.start(1200) #20 minutes = 1200 seconds; i found out that if MySQL socket is idled for 20 minutes or longer, MySQL itself disconnects the session for security reasons; i do believe you can change that in the configuration of the database server itself but it may not be recommended.
                self.reconnect=False
                print "database ping initiated"

        def dbping(self):
                def ping(conn):
                        conn.ping() #what happens here is that twisted allows us to access methods from the MySQLdb module that python posesses; i chose to use the native command instead of sending null commands to the database.
                pingdb=self.dbpool.runWithConnection(ping)
                pingdb.addCallback(self.dbactive)
                pingdb.addErrback(self.dbout)
                print "pinging database"

        def dbactive(self, data):
                if data==None and self.reconnect==True:
                        self.dbping.stop()
                        self.reconnect=False
                        self.dbping.start(1200) #20 minutes = 1200 seconds
                        print "Reconnected to database!"
                elif data==None:
                        print "database is active"

        def dbout(self, deferr):
                #print deferr
                if self.reconnect==False:
                        self.dbreconnect()
                elif self.reconnect==True:
                        print "Unable to reconnect to database"
                print "unable to ping MySQL database!"

        def dbreconnect(self, *data):
                self.dbping.stop()
                self.reconnect=True
                #self.dbping = task.LoopingCall(self.dbping)
                self.dbping.start(60) #60
if __name__ == "__main__":
        db = sqlClass(adbapi.ConnectionPool("MySQLdb", cp_reconnect=True, host="", user="", passwd="", db=""))
        reactor.callLater(2, db.dbping)
        reactor.run()

让我知道它对你有什么影响:)

于 2011-11-16T23:35:37.320 回答