Ticket #4 (new defect)

Opened 10 months ago

@transact re-runs startup() unless broker.ranStart is set by user.

Reported by: kgi Assigned to: edsuom
Priority: major Milestone:
Component: sAsync Version:
Keywords: Cc:

Description

There is a bug in current head-of-code sAsync that causes startup() to run more than once unless the user explicitly takes action to avoid this.

I found this out when I wrapped up a Broker object in a Twisted Service and was running the startup() method from the Service's startService() method. However, the very first method call to a @transact-decorated method would re-call the startup() method.

The reason for this is that database.py:transact.substituteFunction() has the following code:

        if hasattr(self, 'connection') and getattr(self, 'ranStart', False):
            # We already have a connection, let's get right to the transaction

However, when startup() is run manually ahead-of-time (that is, before the first @transact-decorated method is run), self.connection is defined but self.ranStart is not. This is only set in the started() callback, which is unsuitable as a general-purpose callback for the startup() method.

The net result of this is that the code falls through to the else clause at the bottom of substituteFunction():

        else:
            # We need to start things up before doing this first transaction
            d = defer.maybeDeferred(self.startup)
            self._transactionStartupDeferred = d
            d.addCallback(started)
            d.addCallback(lambda _: doTransaction(useSession))

This re-runs the setup() method.

A workaround is to ensure that you manually set the ranStart attribute in your own code; for example, in the context of a Service:

class SASyncBrokerService ( service.Service ):
    def __init__ ( self, broker ):
        self.broker = broker

    def startService ( self ):
        service.Service.startService ( self )
        d = self.broker.startup()
        d.addCallback ( self.brokerStarted )
        return d

    def brokerStarted ( self, r ):
        self.broker.ranStart = True
        return r