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)

最初のいくつかのリクエストは正常に機能しますが、mysqlwait_timeoutの有効期限が切れると、2006年の「Mysqlが消えました」という恐ろしいエラーエラーが表示されます。WSGI 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="")

私はこれをテストしていませんが、テストしたとき、または他の誰かが共有してくれた場合は、いくつかの結果を再投稿します。

私がスクリプトを開発していたとき、私はツイスト8.2.0を使用していました(しばらくツイストに触れていませんでした)、そして当時、フレームワークにはそのような明示的なキープアライブメソッドがなかったので、イベント駆動型パラダイムツイストビルドを使用してping/キープアライブ拡張機能を開発しました直接MySQLdbモジュールのping()メソッドと組み合わせて使用​​します(コードコメントを参照)。私がこの応答を入力していたとき; しかし、私は現在のねじれたドキュメントを見回しましたが、それでも明示的なキープアライブメソッドまたはパラメーターを見つけることができませんでした。私の推測では、twisted自体にはデータベース接続ライブラリ/クラスがありません。Pythonで利用可能なメソッドを使用し、それらのモジュールとのインターフェースの間接的なレイヤーを提供します。使用されているデータベースライブラリへの直接呼び出しの露出があります。これは、adbapi.runWithConnectionメソッドを使用して実行されます。

これが私がtwisted8.2.0とpython2.6で書いたモジュールです。pingの間隔を設定できます。スクリプトが行うことは、20分ごとにデータベースにpingを実行し、失敗した場合は60秒ごとに再接続を試みます。スクリプトが突然の/切断された接続を処理しないことを警告する必要があります。ツイストされたクエリを実行するときはいつでも、addErrbackを介して処理できます。少なくとも、それが私が行った方法です。データベース接続が切断されるたびに、クエリを実行しているときにイベントがエラーバックを発生させたときにのみ接続が確立されているかどうかを確認でき、その時点で処理することに気付きました。基本的に、クエリを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 に答える