S
snacktime
I have a client/server application written in python/twisted and on
freebsd the server won't shut down correctly with SIGINT or SIGTERM,
instead requiring a SIGKILL. The twist is that if I send the server a
signal, it will shut down on the next request from the client. In
that case it shuts down immediately when the client connects and
closes the connection before it's fully established.
The server will also shut down correctly if it hasn't yet accepted any
connections from a client.
This is on freebsd 5.3-release-p2 with python 2.4 and twisted both
installed from ports. I tested it on Debian (sarge) and the signals
work fine.
It's like there is some sort of event loop that isn't working
correctly. Freebsd is obviously getting the signal, but it doesn't
act on it until another request comes in from the client.
Below is some simple code that will run if you have twisted. Sorry I
don't have a more simple test case, but I'm fairly new to python (and
threads), and writing something from scratch would take a while.
Server (save server to test.tac and start with twistd -noy test.tac)
---------------------------------------------------
from twisted.application import service,internet
from twisted.internet.protocol import Protocol, Factory
from twisted.internet import defer, reactor
from twisted.python import threadable
from twisted.internet import threads
from twisted.python import log
threadable.init(1)
import sys
class ProcessTransaction:
def Do(self,data):
return 'Done'
### Protocol Implementation
class OT(Protocol):
def dataReceived(self, data):
"""As soon as any data is received, process it in a thread."""
reactor.callLater(0, self.Start,data)
def PrintData(self,data):
self.transport.write("%s\r\n" % data)
self.transport.loseConnection()
def Start(self,data):
c = ProcessTransaction()
d = threads.deferToThread(c.Do,data)
d.addCallback(self.PrintData)
d.addErrback(log.err)
application = service.Application("otransact")
OTService = service.IServiceCollection(application)
OTfactory = Factory()
OTfactory.protocol = OT
OTServer = internet.TCPServer(8000, OTfactory)
OTServer.setServiceParent(OTService)
Client (just run as python test.py)
--------------------------------------------------------------
import sys
import time
from twisted.internet.protocol import ClientFactory
from twisted.protocols.basic import LineReceiver
from twisted.internet import reactor
class EchoClient(LineReceiver):
end="GoodBye"
def connectionMade(self):
self.sendLine("Testing")
def connectionLost(self, reason):
print 'connection lost (protocol)'
reactor.stop()
def lineReceived(self, line):
print "receive:", line
self.transport.loseConnection()
class EchoClientFactory(ClientFactory):
protocol = EchoClient
def clientConnectionFailed(self, connector, reason):
print 'connection failed:', reason.getErrorMessage()
reactor.stop()
def clientConnectionLost(self, connector, reason):
print 'connection lost:', reason.getErrorMessage()
reactor.stop()
def main():
factory = EchoClientFactory()
reactor.connectTCP('localhost', 8000, factory)
reactor.run()
if __name__ == '__main__':
main()
freebsd the server won't shut down correctly with SIGINT or SIGTERM,
instead requiring a SIGKILL. The twist is that if I send the server a
signal, it will shut down on the next request from the client. In
that case it shuts down immediately when the client connects and
closes the connection before it's fully established.
The server will also shut down correctly if it hasn't yet accepted any
connections from a client.
This is on freebsd 5.3-release-p2 with python 2.4 and twisted both
installed from ports. I tested it on Debian (sarge) and the signals
work fine.
It's like there is some sort of event loop that isn't working
correctly. Freebsd is obviously getting the signal, but it doesn't
act on it until another request comes in from the client.
Below is some simple code that will run if you have twisted. Sorry I
don't have a more simple test case, but I'm fairly new to python (and
threads), and writing something from scratch would take a while.
Server (save server to test.tac and start with twistd -noy test.tac)
---------------------------------------------------
from twisted.application import service,internet
from twisted.internet.protocol import Protocol, Factory
from twisted.internet import defer, reactor
from twisted.python import threadable
from twisted.internet import threads
from twisted.python import log
threadable.init(1)
import sys
class ProcessTransaction:
def Do(self,data):
return 'Done'
### Protocol Implementation
class OT(Protocol):
def dataReceived(self, data):
"""As soon as any data is received, process it in a thread."""
reactor.callLater(0, self.Start,data)
def PrintData(self,data):
self.transport.write("%s\r\n" % data)
self.transport.loseConnection()
def Start(self,data):
c = ProcessTransaction()
d = threads.deferToThread(c.Do,data)
d.addCallback(self.PrintData)
d.addErrback(log.err)
application = service.Application("otransact")
OTService = service.IServiceCollection(application)
OTfactory = Factory()
OTfactory.protocol = OT
OTServer = internet.TCPServer(8000, OTfactory)
OTServer.setServiceParent(OTService)
Client (just run as python test.py)
--------------------------------------------------------------
import sys
import time
from twisted.internet.protocol import ClientFactory
from twisted.protocols.basic import LineReceiver
from twisted.internet import reactor
class EchoClient(LineReceiver):
end="GoodBye"
def connectionMade(self):
self.sendLine("Testing")
def connectionLost(self, reason):
print 'connection lost (protocol)'
reactor.stop()
def lineReceived(self, line):
print "receive:", line
self.transport.loseConnection()
class EchoClientFactory(ClientFactory):
protocol = EchoClient
def clientConnectionFailed(self, connector, reason):
print 'connection failed:', reason.getErrorMessage()
reactor.stop()
def clientConnectionLost(self, connector, reason):
print 'connection lost:', reason.getErrorMessage()
reactor.stop()
def main():
factory = EchoClientFactory()
reactor.connectTCP('localhost', 8000, factory)
reactor.run()
if __name__ == '__main__':
main()