From cb8ac9b56741ac547341de27b7a9333aada93cc3 Mon Sep 17 00:00:00 2001 From: Sergey Shepelev Date: Wed, 10 Aug 2016 11:14:25 +0500 Subject: [PATCH] =?UTF-8?q?tpool:=20isolate=20internal=20socket=20from=20d?= =?UTF-8?q?efault=20timeout;=20Thanks=20to=20Alex=20Villac=C3=ADs=20Lasso?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- AUTHORS | 1 + eventlet/tpool.py | 2 + .../tpool_isolate_socket_default_timeout.py | 15 ++++ tests/tpool_test.py | 68 +++++++++---------- 4 files changed, 52 insertions(+), 34 deletions(-) create mode 100644 tests/isolated/tpool_isolate_socket_default_timeout.py diff --git a/AUTHORS b/AUTHORS index 673b4d3..a34ea56 100644 --- a/AUTHORS +++ b/AUTHORS @@ -134,3 +134,4 @@ Thanks To * Alexis Lee * Steven Erenst * Piët Delport +* Alex Villacís Lasso diff --git a/eventlet/tpool.py b/eventlet/tpool.py index 618c377..1c2dea0 100644 --- a/eventlet/tpool.py +++ b/eventlet/tpool.py @@ -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, diff --git a/tests/isolated/tpool_isolate_socket_default_timeout.py b/tests/isolated/tpool_isolate_socket_default_timeout.py new file mode 100644 index 0000000..fa8e3f6 --- /dev/null +++ b/tests/isolated/tpool_isolate_socket_default_timeout.py @@ -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') diff --git a/tests/tpool_test.py b/tests/tpool_test.py index e1479de..d44ff6b 100644 --- a/tests/tpool_test.py +++ b/tests/tpool_test.py @@ -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)