title: Handling of ConnectionLost exception in twisted
body: <p>I can not handle a ConnectionLost exception.
  Brief example of what I have. First of all iIset up connection to jabber server and ping it. I use wokkel library for that. Then I add errback to the method that is sending ping. In the errback I handle the ConnectionLost error. After that, I close the internet connection. But I can not see if that ConnectionLost is handled. I close connection in my application and all exception handlers are invoked.</p>
  
  <p>Ping goes well.</p>
  
  <pre><code>[XmlStream,client] Ping to JID(u'jabber.ru') started at HivemindPingClientProtocol 
  [-] SEND: «iq to='jabber.ru' type='get' id='H_3'&gt;/&gt;»
  [XmlStream,client] RECV: "/&gt;&lt;feature-not-implemented xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/&gt;"
  </code></pre>
  
  <p>Internet connection is closed</p>
  
  <pre><code>[-] SEND: «iq to='jabber.ru' type='get' id='H_6'&gt;/&gt;»
  [-] SEND: «iq to='jabber.ru' type='get' id='H_7'&gt;/&gt;»
  </code></pre>
  
  <p>Handlers of ConnectionLost are not invoked. "Stream closed at HivemindXMPPClient" is printed in StreamManager in _disconnected method</p>
  
  <pre><code>[-] Protocol stopped
  [-] Protocol closed
  [-] Transport stopped
  [XmlStream,client] Stream closed at HivemindXMPPClient
  </code></pre>
  
  <p>All exception are handled after closing stream.</p>
  
  <pre><code>[XmlStream,client] Failure [Failure instance: Traceback (failure with no frames): &lt;class 'twisted.internet.error.ConnectionLost'&gt;: Connection to the other side was lost in a non-clean fashion.
  [XmlStream,client] Failure [Failure instance: Traceback (failure with no frames): &lt;class 'twisted.internet.error.ConnectionLost'&gt;: Connection to the other side was lost in a non-clean fashion.] 
  [XmlStream,client] Connection lost with [Failure instance: Traceback (failure with no frames): &lt;class 'twisted.internet.error.ConnectionDone'&gt;: Connection was closed cleanly.] 
  [XmlStream,client] Stopping factory &lt;hivemind.network.network_core.HivemindXmlStreamFactory object at 0xa2e904c&gt;&gt; 
  </code></pre>
  
  <p>Can anybody explain why errbacks are invoked after closing the stream? Actually I want to implement a reconnect feature(I already use ReconnectingFactory, but it does not react on ConnectionLost). Can someone give me some example of reconnect implementation in twisted?</p>
  
  <p><strong>Script example.</strong>
  Run this script (make sure that ping work fine). Then close your internet connection. When several ping has occured, you need to terminate the script. As you can see, ConnectionLost errors are handled after closing the connection.</p>
  
  <pre><code>import sys
  from twisted.python import log
  from twisted.words.protocols import jabber
  from twisted.internet.error import ConnectionLost
  from wokkel.client import XMPPClient
  from wokkel.ping import PingClientProtocol
  from twisted.internet.task import LoopingCall
  
  JID = unicode('YOUR@JABBER.ID')
  PASSWORD = 'PASSWORD'
  INTERVAL = 3
  
  class SpecialPingClientProtocol(PingClientProtocol):
  
      def __init__(self, entity, interval):
          self.__entity = jabber.jid.internJID(entity)
          self.__interval = interval
          self.__pingLoop = None
  
      def _onError(self, failure):
          log.msg('Failure %s at %s' % (failure, self.__class__.__name__))
          error = failure.trap(jabber.error.StanzaError, ConnectionLost)
          if error == jabber.error.StanzaError:
              if failure.value.condition == 'feature-not-implemented':
                  return None
          elif error == ConnectionLost:
              # Do some beautiful things
              log.msg('Connection is lost. I want to reconnect NOW')
          return failure
  
      def _sendPing(self):
          defer = self.ping(self.__entity)
          defer.addErrback(self._onError)
  
      def stopPing(self):
          log.msg('Ping to %s stopped at %s' % (self.__entity, self.__class__.__name__))
          if self.__pingLoop is not None and self.__pingLoop.running:
              self.__pingLoop.stop()
              self.__pingLoop = None
  
      def startPing(self):
          log.msg('Ping to %s started at %s ' % (self.__entity, self.__class__.__name__))
          self.__pingLoop = LoopingCall(self._sendPing)
          self.__pingLoop.start(self.__interval, now = False)
  
  def main():
      log.startLogging(sys.stdout)
      transport = XMPPClient(jabber.jid.internJID(JID), PASSWORD)
      transport.logTraffic = True
      pinger = SpecialPingClientProtocol(JID, INTERVAL)
      pinger.setHandlerParent(transport)
      transport.startService()
      pinger.startPing()
      reactor.run()
  
  if __name__ == '__main__':
      from twisted.internet import reactor
      main()
  </code></pre>