[Twisted-Python] timeout and retries

Stefano Canepa sc at linux.it
Fri Jun 17 10:41:17 EDT 2005


The following code is a try to write a protocol with timeout and
retries. The connectioMade is used only as a test. I have some problems:
1) even if I placed "\x01" as delimiter the line is sent not terminated
2) even if timeout expired 3 times the success callback is called

Were is my mistake?

Secondly I will prefer to leave the protocol as simple as passible and
put all implementation details into the factory. I was unable to do
this, any suggestion would be of big help.

Thanks very much
Stefano

#!/usr/bin/env python
#
# Twisted modules 
#
from twisted.internet.protocol import ClientFactory
from twisted.protocols.basic import LineReceiver
from twisted.internet import reactor, defer
#
# Python modules
#
import re
#
# if it exists load configuration file
#
try:
    import HL7LLPClientConfig
except:
    #
    # else use defaults
    #
    TIMEOUT = 10
    PORT = 3000
    SERVER = 'localhost'
    RETRIES = 3
    pass

class HL7LLPClientProtocol(LineReceiver):
    """
    HL7 Lower Level Protocol initiating module implementation.
    It sends a packet, waits ACK/NACK or timeout in case of failure
    retries RETRIES times
    """
    # delimiter is set to <EB> (\x02 i.e. STX) so that the whole HL7
message
    # can be considered as a string
    delimiter = "\x02"
    msg = ""

    def __init__(self):
        self.ackMSG = re.compile("\x01\x06")
        self.nackMSG = re.compile("\x01\x15")

    def connectionMade(self):
        self.sendMsg("MSH|||||||||||")
        
    def sendMsg(self, msg, numRetries=RETRIES):
        """
        Store the message to be used by derived classes, send the
message and
        return a deferred
        """
        self.msg = msg
        self.sendLine(msg)
        return self.timeoutAndRetry(numRetries)
        
    def sendLine(self, msg):
        """
        Add <SB> (\x01 i.e. SOH) at the start of message as required by
        HL7 standard and send the message
        """
        msgToSend = "\x01"+msg
        print msgToSend
        self.transport.write(msgToSend)
        print "written"

    def lineReceived(self, response):
        """
        It receives the answer store it for use in the derived class and
        verify if it is ACK or NACK to cancel the timeout, every other
        string received is not valid answer so timeout continues to tick
        """
        m = self.ackMSG.match(response)
        n = self.nackMSG.match(response)
        if m or n:
            self.delayedCall.cancel()
            self.delayedCall = None  
        self.somethingResult.callback()
        self.somethingResult = None

    def timeoutAndRetry(self, n):
        """
        Create a deferred, fire the delayedCall, and return the deferred
        """
        d = defer.Deferred() 
        d.addErrback(self.tooManyRetries)
        d.addCallback(self.success)
        c = reactor.callLater(10, self._timeout, n)
        self.somethingResult, self.delayedCall = d, c
        return d
 
    def _timeout(self, n):
        """
        Retry to send if possible or raise and exception
        """
        print n
        if n > 0:
            d = self.somethingResult
            #self.sendMsg(self.msg, n - 1).chainDeferred(d)
            self.sendMsg(self.msg, n - 1)
        else:
            self.somethingResult.errback(Exception("TooManyRetries"))
            self.somethingResult = None

    def timeOutFailure(self, reason):
        """
        Don't know what to do in case of timeout
        """
        print "timeout failure %s " % reason

    def tooManyRetries(self, reason):
        """
        Don't know what to do in case of non timeout failure
        """
        print "non timeout failure %s" % reason

    def success(self, reason):
        """
        Don't know what to do in case of success
        """
        print "success %s" % reason
        
class HL7LLPClientFactory(ClientFactory):
   
    protocol = HL7LLPClientProtocol

def main():
    factory = HL7LLPClientFactory()
    reactor.connectTCP(SERVER, PORT, factory)
    reactor.run()

if __name__ == "__main__":
    main()


-- 
Stefano Canepa aka sc: sc at linux.it  http://www.stefanocanepa.it
Three great virtues of a programmer: laziness, impatience and hubris.
Le tre grandi virtù di un programmatore: pigrizia, impazienza e arroganza.
                                                              (Larry Wall)
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: This is a digitally signed message part
Url : http://twistedmatrix.com/pipermail/twisted-python/attachments/20050617/33b9b72f/attachment.pgp 


More information about the Twisted-Python mailing list