tpool: isolate internal socket from default timeout; Thanks to Alex Villacís Lasso

Since commit f37a87b the internal implementation of tpool uses sockets
instead of pipes for communication. If, for whatever reason, the user code
calls socket.setdefaulttimeout() with some nonzero value, tpool's internal
socket now inherits this timeout. This causes the tpool to receive
a `socket.timeout` exception where none was expected.
https://github.com/eventlet/eventlet/pull/330
This commit is contained in:
Sergey Shepelev
2016-08-10 11:14:25 +05:00
parent db415e58b3
commit cb8ac9b567
4 changed files with 52 additions and 34 deletions

View File

@@ -134,3 +134,4 @@ Thanks To
* Alexis Lee
* Steven Erenst
* Piët Delport
* Alex Villacís Lasso

View File

@@ -276,9 +276,11 @@ def setup():
csock.connect(sock.getsockname())
csock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, True)
_wsock, _addr = sock.accept()
_wsock.settimeout(None)
_wsock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, True)
sock.close()
_rsock = greenio.GreenSocket(csock)
_rsock.settimeout(None)
for i in six.moves.range(_nthreads):
t = threading.Thread(target=tworker,

View File

@@ -0,0 +1,15 @@
__test__ = False
if __name__ == '__main__':
import eventlet
import eventlet.tpool
import socket
def do():
eventlet.sleep(0.2)
return True
socket.setdefaulttimeout(0.05)
result = eventlet.tpool.execute(do)
assert result
print('pass')

View File

@@ -22,7 +22,7 @@ import time
import eventlet
from eventlet import tpool, debug, event
from eventlet.support import six
from tests import LimitedTestCase, skip_with_pyevent, main
import tests
one = 1
@@ -39,7 +39,7 @@ def raise_exception():
raise RuntimeError("hi")
class TestTpool(LimitedTestCase):
class TestTpool(tests.LimitedTestCase):
def setUp(self):
super(TestTpool, self).setUp()
@@ -47,7 +47,7 @@ class TestTpool(LimitedTestCase):
tpool.killall()
super(TestTpool, self).tearDown()
@skip_with_pyevent
@tests.skip_with_pyevent
def test_wrap_tuple(self):
my_tuple = (1, 2)
prox = tpool.Proxy(my_tuple)
@@ -55,7 +55,7 @@ class TestTpool(LimitedTestCase):
self.assertEqual(prox[1], 2)
self.assertEqual(len(my_tuple), 2)
@skip_with_pyevent
@tests.skip_with_pyevent
def test_wrap_string(self):
my_object = "whatever"
prox = tpool.Proxy(my_object)
@@ -63,7 +63,7 @@ class TestTpool(LimitedTestCase):
self.assertEqual(len(my_object), len(prox))
self.assertEqual(my_object.join(['a', 'b']), prox.join(['a', 'b']))
@skip_with_pyevent
@tests.skip_with_pyevent
def test_wrap_uniterable(self):
prox = tpool.Proxy([])
@@ -76,7 +76,7 @@ class TestTpool(LimitedTestCase):
self.assertRaises(IndexError, index)
self.assertRaises(TypeError, key)
@skip_with_pyevent
@tests.skip_with_pyevent
def test_wrap_dict(self):
my_object = {'a': 1}
prox = tpool.Proxy(my_object)
@@ -85,7 +85,7 @@ class TestTpool(LimitedTestCase):
self.assertEqual(str(my_object), str(prox))
self.assertEqual(repr(my_object), repr(prox))
@skip_with_pyevent
@tests.skip_with_pyevent
def test_wrap_module_class(self):
prox = tpool.Proxy(re)
self.assertEqual(tpool.Proxy, type(prox))
@@ -93,7 +93,7 @@ class TestTpool(LimitedTestCase):
self.assertEqual(exp.groups, 3)
assert repr(prox.compile)
@skip_with_pyevent
@tests.skip_with_pyevent
def test_wrap_eq(self):
prox = tpool.Proxy(re)
exp1 = prox.compile('.')
@@ -102,12 +102,12 @@ class TestTpool(LimitedTestCase):
exp3 = prox.compile('/')
assert exp1 != exp3
@skip_with_pyevent
@tests.skip_with_pyevent
def test_wrap_ints(self):
p = tpool.Proxy(4)
assert p == 4
@skip_with_pyevent
@tests.skip_with_pyevent
def test_wrap_hash(self):
prox1 = tpool.Proxy('' + 'A')
prox2 = tpool.Proxy('A' + '')
@@ -118,7 +118,7 @@ class TestTpool(LimitedTestCase):
proxList = tpool.Proxy([])
self.assertRaises(TypeError, hash, proxList)
@skip_with_pyevent
@tests.skip_with_pyevent
def test_wrap_nonzero(self):
prox = tpool.Proxy(re)
exp1 = prox.compile('.')
@@ -126,7 +126,7 @@ class TestTpool(LimitedTestCase):
prox2 = tpool.Proxy([1, 2, 3])
assert bool(prox2)
@skip_with_pyevent
@tests.skip_with_pyevent
def test_multiple_wraps(self):
prox1 = tpool.Proxy(re)
prox2 = tpool.Proxy(re)
@@ -135,18 +135,18 @@ class TestTpool(LimitedTestCase):
del x2
prox2.compile('.')
@skip_with_pyevent
@tests.skip_with_pyevent
def test_wrap_getitem(self):
prox = tpool.Proxy([0, 1, 2])
self.assertEqual(prox[0], 0)
@skip_with_pyevent
@tests.skip_with_pyevent
def test_wrap_setitem(self):
prox = tpool.Proxy([0, 1, 2])
prox[1] = 2
self.assertEqual(prox[1], 2)
@skip_with_pyevent
@tests.skip_with_pyevent
def test_wrap_iterator(self):
self.reset_timeout(2)
prox = tpool.Proxy(range(10))
@@ -155,7 +155,7 @@ class TestTpool(LimitedTestCase):
result.append(i)
self.assertEqual(list(range(10)), result)
@skip_with_pyevent
@tests.skip_with_pyevent
def test_wrap_iterator2(self):
self.reset_timeout(5) # might take a while due to imprecise sleeping
@@ -184,7 +184,7 @@ class TestTpool(LimitedTestCase):
assert counter[0] > 10, counter[0]
gt.kill()
@skip_with_pyevent
@tests.skip_with_pyevent
def test_raising_exceptions(self):
prox = tpool.Proxy(re)
@@ -196,7 +196,7 @@ class TestTpool(LimitedTestCase):
prox = tpool.Proxy(tpool_test)
self.assertRaises(RuntimeError, prox.raise_exception)
@skip_with_pyevent
@tests.skip_with_pyevent
def test_variable_and_keyword_arguments_with_function_calls(self):
import optparse
parser = tpool.Proxy(optparse.OptionParser())
@@ -204,7 +204,7 @@ class TestTpool(LimitedTestCase):
opts, args = parser.parse_args(["-nfoo"])
self.assertEqual(opts.n, 'foo')
@skip_with_pyevent
@tests.skip_with_pyevent
def test_contention(self):
from tests import tpool_test
prox = tpool.Proxy(tpool_test)
@@ -216,19 +216,19 @@ class TestTpool(LimitedTestCase):
results = list(pile)
self.assertEqual(len(results), 3)
@skip_with_pyevent
@tests.skip_with_pyevent
def test_timeout(self):
import time
eventlet.Timeout(0.1, eventlet.TimeoutError())
self.assertRaises(eventlet.TimeoutError,
tpool.execute, time.sleep, 0.3)
@skip_with_pyevent
@tests.skip_with_pyevent
def test_killall(self):
tpool.killall()
tpool.setup()
@skip_with_pyevent
@tests.skip_with_pyevent
def test_killall_remaining_results(self):
semaphore = event.Event()
@@ -244,7 +244,7 @@ class TestTpool(LimitedTestCase):
tpool.killall()
gt.wait()
@skip_with_pyevent
@tests.skip_with_pyevent
def test_autowrap(self):
x = tpool.Proxy({'a': 1, 'b': 2}, autowrap=(int,))
assert isinstance(x.get('a'), tpool.Proxy)
@@ -255,7 +255,7 @@ class TestTpool(LimitedTestCase):
assert isinstance(x.one, tpool.Proxy)
assert not isinstance(x.none, tpool.Proxy)
@skip_with_pyevent
@tests.skip_with_pyevent
def test_autowrap_names(self):
x = tpool.Proxy({'a': 1, 'b': 2}, autowrap_names=('get',))
assert isinstance(x.get('a'), tpool.Proxy)
@@ -265,7 +265,7 @@ class TestTpool(LimitedTestCase):
assert isinstance(x.one, tpool.Proxy)
assert not isinstance(x.two, tpool.Proxy)
@skip_with_pyevent
@tests.skip_with_pyevent
def test_autowrap_both(self):
from tests import tpool_test
x = tpool.Proxy(tpool_test, autowrap=(int,), autowrap_names=('one',))
@@ -273,7 +273,7 @@ class TestTpool(LimitedTestCase):
# violating the abstraction to check that we didn't double-wrap
assert not isinstance(x._obj, tpool.Proxy)
@skip_with_pyevent
@tests.skip_with_pyevent
def test_callable(self):
def wrapped(arg):
return arg
@@ -284,7 +284,7 @@ class TestTpool(LimitedTestCase):
assert isinstance(x(4), tpool.Proxy)
self.assertEqual("4", str(x(4)))
@skip_with_pyevent
@tests.skip_with_pyevent
def test_callable_iterator(self):
def wrapped(arg):
yield arg
@@ -295,22 +295,22 @@ class TestTpool(LimitedTestCase):
for r in x(3):
self.assertEqual(3, r)
@skip_with_pyevent
@tests.skip_with_pyevent
def test_eventlet_timeout(self):
def raise_timeout():
raise eventlet.Timeout()
self.assertRaises(eventlet.Timeout, tpool.execute, raise_timeout)
@skip_with_pyevent
@tests.skip_with_pyevent
def test_tpool_set_num_threads(self):
tpool.set_num_threads(5)
self.assertEqual(5, tpool._nthreads)
class TpoolLongTests(LimitedTestCase):
class TpoolLongTests(tests.LimitedTestCase):
TEST_TIMEOUT = 60
@skip_with_pyevent
@tests.skip_with_pyevent
def test_a_buncha_stuff(self):
assert_ = self.assert_
@@ -339,7 +339,7 @@ class TpoolLongTests(LimitedTestCase):
self.assertEqual(len(results), cnt)
tpool.killall()
@skip_with_pyevent
@tests.skip_with_pyevent
def test_leakage_from_tracebacks(self):
tpool.execute(noop) # get it started
gc.collect()
@@ -362,5 +362,5 @@ class TpoolLongTests(LimitedTestCase):
tpool.killall()
if __name__ == '__main__':
main()
def test_isolate_from_socket_default_timeout():
tests.run_isolated('tpool_isolate_socket_default_timeout.py', timeout=1)