mirror of
https://github.com/valitydev/thrift.git
synced 2024-11-07 18:58:51 +00:00
bcaa2ad0d6
When a function called by the forking python thrift server throws an exception the client will hang. This happens because the parent of the forked process does not properly close the socket fd. Under normal operation the server operation completes and returns a value to the client. However, when an exception occurs the 'end' message is never sent to the client so the client relies on a connection close to abort the call (this is how the threading server works I believe). This fails with the forking server because the parent process never closes the socket fd. The child has closed the fd at this point, but the connection will not actually be closed until all open instances of the fd are closed. Since the client is waiting for a message and the server never closes it the client is forced to wait until a read timeout occurs many minutes later. This diff closes the parent's copy of the socket fd immediately after the fork occurs. I modified my load test server to throw an exception. The client did not hang. git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@666363 13f79535-47bb-0310-9956-ffa450edef68
118 lines
3.3 KiB
Python
Executable File
118 lines
3.3 KiB
Python
Executable File
#!/usr/bin/env python
|
|
|
|
import sys, glob
|
|
sys.path.insert(0, './gen-py')
|
|
sys.path.insert(0, glob.glob('../../lib/py/build/lib.*')[0])
|
|
|
|
from ThriftTest import ThriftTest
|
|
from ThriftTest.ttypes import *
|
|
from thrift.transport import TTransport
|
|
from thrift.transport import TSocket
|
|
from thrift.protocol import TBinaryProtocol
|
|
import unittest
|
|
import time
|
|
from optparse import OptionParser
|
|
|
|
|
|
parser = OptionParser()
|
|
|
|
parser.add_option("--port", type="int", dest="port", default=9090)
|
|
parser.add_option("--host", type="string", dest="host", default='localhost')
|
|
parser.add_option("--framed-input", action="store_true", dest="framed_input")
|
|
parser.add_option("--framed-output", action="store_false", dest="framed_output")
|
|
|
|
(options, args) = parser.parse_args()
|
|
|
|
class AbstractTest(unittest.TestCase):
|
|
|
|
def setUp(self):
|
|
global options
|
|
|
|
socket = TSocket.TSocket(options.host, options.port)
|
|
|
|
# Frame or buffer depending upon args
|
|
if options.framed_input or options.framed_output:
|
|
self.transport = TTransport.TFramedTransport(socket, options.framed_input, options.framed_output)
|
|
else:
|
|
self.transport = TTransport.TBufferedTransport(socket)
|
|
|
|
self.transport.open()
|
|
|
|
protocol = self.protocol_factory.getProtocol(self.transport)
|
|
self.client = ThriftTest.Client(protocol)
|
|
|
|
def tearDown(self):
|
|
# Close!
|
|
self.transport.close()
|
|
|
|
def testVoid(self):
|
|
self.client.testVoid()
|
|
|
|
def testString(self):
|
|
self.assertEqual(self.client.testString('Python'), 'Python')
|
|
|
|
def testByte(self):
|
|
self.assertEqual(self.client.testByte(63), 63)
|
|
|
|
def testI32(self):
|
|
self.assertEqual(self.client.testI32(-1), -1)
|
|
self.assertEqual(self.client.testI32(0), 0)
|
|
|
|
def testI64(self):
|
|
self.assertEqual(self.client.testI64(-34359738368), -34359738368)
|
|
|
|
def testDouble(self):
|
|
self.assertEqual(self.client.testDouble(-5.235098235), -5.235098235)
|
|
|
|
def testStruct(self):
|
|
x = Xtruct()
|
|
x.string_thing = "Zero"
|
|
x.byte_thing = 1
|
|
x.i32_thing = -3
|
|
x.i64_thing = -5
|
|
y = self.client.testStruct(x)
|
|
|
|
self.assertEqual(y.string_thing, "Zero")
|
|
self.assertEqual(y.byte_thing, 1)
|
|
self.assertEqual(y.i32_thing, -3)
|
|
self.assertEqual(y.i64_thing, -5)
|
|
|
|
def testException(self):
|
|
self.client.testException('Safe')
|
|
try:
|
|
self.client.testException('Xception')
|
|
self.fail("should have gotten exception")
|
|
except Xception, x:
|
|
self.assertEqual(x.errorCode, 1001)
|
|
self.assertEqual(x.message, 'Xception')
|
|
|
|
try:
|
|
self.client.testException("throw_undeclared")
|
|
self.fail("should have thrown exception")
|
|
except Exception: # type is undefined
|
|
pass
|
|
|
|
def testAsync(self):
|
|
start = time.time()
|
|
self.client.testAsync(2)
|
|
end = time.time()
|
|
self.assertTrue(end - start < 0.2,
|
|
"async sleep took %f sec" % (end - start))
|
|
|
|
class NormalBinaryTest(AbstractTest):
|
|
protocol_factory = TBinaryProtocol.TBinaryProtocolFactory()
|
|
|
|
class AcceleratedBinaryTest(AbstractTest):
|
|
protocol_factory = TBinaryProtocol.TBinaryProtocolAcceleratedFactory()
|
|
|
|
def suite():
|
|
suite = unittest.TestSuite()
|
|
loader = unittest.TestLoader()
|
|
|
|
suite.addTest(loader.loadTestsFromTestCase(NormalBinaryTest))
|
|
suite.addTest(loader.loadTestsFromTestCase(AcceleratedBinaryTest))
|
|
return suite
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main(defaultTest="suite", testRunner=unittest.TextTestRunner(verbosity=2))
|