扭曲的Web服务 - sql连接丢失

时间:2011-11-16 22:18:07

标签: python web-services twisted mysql-connect

我正在开发一个使用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)

前几个请求工作正常,但在mysqls wait_timeout到期后,恐惧错误2006“Mysql已经消失”错误表面。据我所知,对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

1 个答案:

答案 0 :(得分:2)

我正在开发一个带有扭曲的软件,我不得不利用一个不变的MySQL数据库连接。我确实遇到了这个问题并广泛地挖掘了扭曲的文档并发布了一些我无法找到正确解决方案的问题。当你实例化adbapi.connectionPool类时,你可以传递一个布尔参数;然而它似乎永远不会工作,我不断得到错误。但是,我猜测重新连接boolean表示当SQL断开连接时,连接对象的破坏。

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

我没有对此进行过测试,但是当我这样做或者其他人请分享时我会重新发布一些结果。

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

这是我在扭曲的8.2.0和python 2.6下编写的模块;你可以设置ping之间的间隔。脚本的作用是每20分钟对数据库进行一次ping操作,如果失败,它会每隔60秒重新连接一次。我必须警告脚本不处理突然/断开的连接;每当你通过扭曲运行查询时,你可以通过addErrback处理,至少我是怎么做到的。我注意到,每当数据库连接断开时,您只能在执行查询时查明它是否有,并且事件会引发错误,然后在此时处理它。基本上,如果我不运行查询10分钟,并且我的数据库断开连接,我的应用程序将不会实时响应。应用程序将在运行后续查询时意识到连接已被删除;所以数据库可能在第一次查询,5,9等后1分钟断开了我们.... 我想这可以追溯到我所说的最初的想法,扭曲利用python自己的库或第三方库进行数据库连接,因此,有些事情的处理方式有点不同。



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()

让我知道它是如何为您服务的:)