When does an inverted adbapi transaction actually occur?

I am using adbapi on a cyclone web server. First, my handler writes some things to the SQL database, and then makes an HTTP request to another web server. If this HTTP request failed, I want the database transaction to be rolled back. However, I do not get such an effect. Reviewing the documentation, he says

The function will be called in a thread with twisted.enterprise.adbapi.Transaction, which basically mimics the DB-API cursor. In all cases, the database transaction will be completed after your use of the database is completed, unless the exception is in which case it will be rolled back.

This is not an exact statement, as we would like. At what point does my "database usage" exactly end? This is when the self.finish () method of the handler is called? When is the method passed to ConnectionPool.runInteraction () completed?

Here is my code

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) 

If the web server displays an error message or the connection to it expires, or mainly if the code passes the saveStuffToDatabase method, nothing is rolled back when an error occurs.

I assume that this means that the transaction was completed when the method passed to ConnectionPool.runInteraction () completed without exception. If in this case, I think, then I would have to include everything all the time, including calling the web server inside saveStuffToDatabase ()?

+4
source share
1 answer

Well, I redefined the code using synchronous calls and it works correctly. Looking at the documentation for the runInteraction () method, he made it a little clearer:

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

Interact with the database and return the result. An β€œinteraction” is a callable that will be executed in a thread using a federated connection. It will be passed to the Transaction object as an argument (whose interface is identical to the database cursor interface for the DB-API module you selected), and its results will be returned as deferred. If starting the method throws an exception, the transaction will be discarded. If the method returns, the transaction will be completed.

+2
source

Source: https://habr.com/ru/post/1436254/


All Articles