4

CycloneWebサーバーでadbapiを使用しています。最初に私のハンドラーはSQLデータベースにいくつかのものを書き込み、次に別のWebサーバーへのHTTP要求を行います。そのHTTPリクエストが失敗した場合、データベーストランザクションをロールバックしたいと思います。しかし、私はその効果を得ていません。ドキュメントを見ると、

関数は、twisted.enterprise.adbapi.Transactionを使用してスレッドで呼び出されます。これは、基本的にDB-APIカーソルを模倣しています。すべての場合において、データベーストランザクションは、データベースの使用が終了した後にコミットされます。ただし、例外が発生した場合は、ロールバックされます。

これは私が望むほど正確なステートメントではありません。私の「データベースの使用は正確にどの時点で終了」しますか?それは、ハンドラーのself.finish()メソッドが呼び出されたときですか?ConnectionPool.runInteraction()に渡されたメソッドが実行されると?

これが私のコードです

class AccountCreationHandler(BaseRequestHandler):
    @cyclone.web.asynchronous
    def post(self, accessKey, *args, **kwargs):
        try:    
            d = connPool.runInteraction(self.saveStuffToDatabase)
            d.addCallback(self.callWebServer)
            d.addCallback(self.formatResult)
            d.addErrback(self.handleFailure)

        except Exception, e:
            self.handleException(e)


    def saveStuffToDatabase(self, txn):
        txn.execute("INSERT INTO Table1 (f1) VALUES ('v1')")


    def callWebServer(self):
        agent = Agent(reactor)
        hdrs = Headers({ "Content-type": ["application/json"] })
        values = json.dumps({ "someField": 123 })
        body = SimpleProducer(values)
        url = "http://somewebserver.com"
        d = agent.request("POST", url, hdrs, body)
        d.addCallback(self.handleWebResponse)
        return d


    def handleWebResponse(self, response):
        if response.code == 200:
            d = Deferred()
            receiver = SimpleReceiver(d)
            response.deliverBody(receiver)
            d.addCallback(self.saveWebServerResults)
            return d
        else:
            raise Exception("web server failed with http status code %d" % response.code)


    def saveWebServerResults(self, body):
        self.results = body


    def formatResult(self):    
        self.finish(self.results)


class SimpleProducer(object):
    implements(IBodyProducer)

    def __init__(self, body):
        self.body = body
        self.length = len(body)

    def startProducing(self, consumer):
        consumer.write(self.body)
        return succeed(None)

    def pauseProducing(self):
        pass

    def stopProducing(self):
        pass


class SimpleReceiver(Protocol):
    def __init__(self, d):
        self.buf = ''
        self.d = d

    def dataReceived(self, data):
        self.buf += data

    def connectionLost(self, reason):
        if type(reason.value) == ResponseDone:
            self.d.callback(self.buf)
        else:
            self.d.errback(reason)

Webサーバーがエラーをスローした場合、またはWebサーバーへの接続がタイムアウトした場合、または基本的にコードがsaveStuffToDatabaseメソッドを通過した場合、エラーが発生しても何もロールバックされません。

これは、ConnectionPool.runInteraction()に渡されたメソッドが例外をスローせずに終了したときに、トランザクションがコミットされることを意味していると思います。その場合、Webサーバーへの呼び出しを含むすべてをsaveStuffToDatabase()内に同期的に配置する必要があると思いますか?

4

1 に答える 1

1

同期呼び出しを使用してコードを再実装しましたが、正しく機能しているようです。runInteraction()メソッドのドキュメントを見ると、もう少し明確になっています。

def runInteraction(self、interaction、* args、** kw):

データベースと対話し、結果を返します。「相互作用」は、プールされた接続を使用してスレッドで実行される呼び出し可能なオブジェクトです。引数としてTransactionオブジェクトが渡され(そのインターフェイスは、選択したDB-APIモジュールのデータベースカーソルのインターフェイスと同じです)、その結果はDeferredとして返されます。メソッドを実行すると例外が発生した場合、トランザクションはロールバックされます。メソッドが値を返す場合、トランザクションはコミットされます。

于 2012-10-03T16:12:27.537 に答える