[Twisted-Python] stop/start client connections with loseConnection in ReconnectingClientFactory
Chris Satterthwaite
chris at cmsconstruct.com
Fri Mar 22 11:08:19 MDT 2019
Hello community,
First of all - thanks for an awesome platform! I'm brand new to this
community, but have been using Twisted a couple years.
Reason for posting:
I've hit a condition with ReconnectingClientFactory that I'm not sure is per
design. I have a work around right now, but need your perspective. Seems
like there should be a better/right way to do this.
Attempted design:
I'd like to have long running TCP clients (forever until stopped), with a
long running TCP server. When a long running client hits a problem with a
dependency (database is down, kafka bus unavailable, external API not
responding, etc), I want the client to go offline for a while and then come
back online. an automated, self-recovery type action. Since it's not ok to
start/stop/restart the Twisted Reactor, I am letting the client finish
whatever it can do, disconnect from the service, destruct the dependencies,
wait for a period of time, and then attempt a clean re-initialization of
those dependencies along with reconnecting to the Twisted Server.
Problem case:
I'm using the ReconnectingClientFactory in my client. When the client hits
a problem, it calls transport.loseConnection(). But whenever the client
calls this, after the disconnect - it does not reconnect; stopFactory is
called and everything exits.
Work around:
I noticed some Twisted source code that works off factory.numPorts. If
numPorts is 1 and the client loses the connection, it goes to 0 and calls
the cleanup. So I conditionally increase this number right before
intentionally disconnecting, and then reset that after reconnecting. This
solves the problem, but it's a hack.
I'll attach the test scripts to this post (if attachments are allowed), but
the main code is with these functions in the factory:
def clientConnectionLost(self, connector, reason):
print(' factory clientConnectionLost:
reason: {}'.format(reason))
# if self.disconnectedOnPurpose:
# ## Hack to keep reactor alive
# print(' factory
clientConnectionLost: increasing numPorts')
# self.numPorts += 1
# self.numPortsChanged = True
# self.disconnectedOnPurpose =
False
print(' ... simulate client going idle
before attempting restart...')
time.sleep(5)
ReconnectingClientFactory.clientConnectionLost(self, connector, reason)
print(' factory clientConnectionLost:
end.\n')
def clientConnectionMade(self):
print(' factory clientConnectionMade:
starting numPorts: {}'.format(self.numPorts))
# if self.numPortsChanged :
# ## Resetting from hacked value
# print(' factory
clientConnectionMade: decreasing numPorts')
# self.numPorts -= 1
# self.numPortsChanged = False
print(' factory clientConnectionMade:
finished numPorts: {}'.format(self.numPorts))
def cleanup(self):
print('factory cleanup: calling
loseConnection')
if self.connectedClient is not None:
self.connectedClient.transport.loseConnection()
self.disconnectedOnPurpose =
True
With the above lines commented out, once the cleanup call does
transport.loseConnection(), the factory stops at the end of
clientConnectionLost.
Sample scripts/logs:
I've tried to create short test scripts and corresponding logs (with the
client failing, and then with it restarting when I use the workaround).
I've cut out several thousand lines to get down to something simple for the
example test scripts, but I know the client is still a little long. Again,
I'm not sure if attachments work on the mailing list, but I'll attempt to
attach the client/server scripts with the corresponding pass/fail logs.
Thanks!
-Chris
-------------- next part --------------
An HTML attachment was scrubbed...
URL: </pipermail/twisted-python/attachments/20190322/df901b5a/attachment-0001.html>
-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: testClient.py
URL: </pipermail/twisted-python/attachments/20190322/df901b5a/attachment-0002.ksh>
-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: testServer.py
URL: </pipermail/twisted-python/attachments/20190322/df901b5a/attachment-0003.ksh>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: client_not_working.log
Type: application/octet-stream
Size: 1280 bytes
Desc: not available
URL: </pipermail/twisted-python/attachments/20190322/df901b5a/attachment-0003.obj>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: client_working_with_hack.log
Type: application/octet-stream
Size: 2139 bytes
Desc: not available
URL: </pipermail/twisted-python/attachments/20190322/df901b5a/attachment-0004.obj>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: server.log
Type: application/octet-stream
Size: 682 bytes
Desc: not available
URL: </pipermail/twisted-python/attachments/20190322/df901b5a/attachment-0005.obj>
More information about the Twisted-Python
mailing list