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:
1
AUTHORS
1
AUTHORS
@@ -134,3 +134,4 @@ Thanks To
|
|||||||
* Alexis Lee
|
* Alexis Lee
|
||||||
* Steven Erenst
|
* Steven Erenst
|
||||||
* Piët Delport
|
* Piët Delport
|
||||||
|
* Alex Villacís Lasso
|
||||||
|
@@ -276,9 +276,11 @@ def setup():
|
|||||||
csock.connect(sock.getsockname())
|
csock.connect(sock.getsockname())
|
||||||
csock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, True)
|
csock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, True)
|
||||||
_wsock, _addr = sock.accept()
|
_wsock, _addr = sock.accept()
|
||||||
|
_wsock.settimeout(None)
|
||||||
_wsock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, True)
|
_wsock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, True)
|
||||||
sock.close()
|
sock.close()
|
||||||
_rsock = greenio.GreenSocket(csock)
|
_rsock = greenio.GreenSocket(csock)
|
||||||
|
_rsock.settimeout(None)
|
||||||
|
|
||||||
for i in six.moves.range(_nthreads):
|
for i in six.moves.range(_nthreads):
|
||||||
t = threading.Thread(target=tworker,
|
t = threading.Thread(target=tworker,
|
||||||
|
15
tests/isolated/tpool_isolate_socket_default_timeout.py
Normal file
15
tests/isolated/tpool_isolate_socket_default_timeout.py
Normal 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')
|
@@ -22,7 +22,7 @@ import time
|
|||||||
import eventlet
|
import eventlet
|
||||||
from eventlet import tpool, debug, event
|
from eventlet import tpool, debug, event
|
||||||
from eventlet.support import six
|
from eventlet.support import six
|
||||||
from tests import LimitedTestCase, skip_with_pyevent, main
|
import tests
|
||||||
|
|
||||||
|
|
||||||
one = 1
|
one = 1
|
||||||
@@ -39,7 +39,7 @@ def raise_exception():
|
|||||||
raise RuntimeError("hi")
|
raise RuntimeError("hi")
|
||||||
|
|
||||||
|
|
||||||
class TestTpool(LimitedTestCase):
|
class TestTpool(tests.LimitedTestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestTpool, self).setUp()
|
super(TestTpool, self).setUp()
|
||||||
|
|
||||||
@@ -47,7 +47,7 @@ class TestTpool(LimitedTestCase):
|
|||||||
tpool.killall()
|
tpool.killall()
|
||||||
super(TestTpool, self).tearDown()
|
super(TestTpool, self).tearDown()
|
||||||
|
|
||||||
@skip_with_pyevent
|
@tests.skip_with_pyevent
|
||||||
def test_wrap_tuple(self):
|
def test_wrap_tuple(self):
|
||||||
my_tuple = (1, 2)
|
my_tuple = (1, 2)
|
||||||
prox = tpool.Proxy(my_tuple)
|
prox = tpool.Proxy(my_tuple)
|
||||||
@@ -55,7 +55,7 @@ class TestTpool(LimitedTestCase):
|
|||||||
self.assertEqual(prox[1], 2)
|
self.assertEqual(prox[1], 2)
|
||||||
self.assertEqual(len(my_tuple), 2)
|
self.assertEqual(len(my_tuple), 2)
|
||||||
|
|
||||||
@skip_with_pyevent
|
@tests.skip_with_pyevent
|
||||||
def test_wrap_string(self):
|
def test_wrap_string(self):
|
||||||
my_object = "whatever"
|
my_object = "whatever"
|
||||||
prox = tpool.Proxy(my_object)
|
prox = tpool.Proxy(my_object)
|
||||||
@@ -63,7 +63,7 @@ class TestTpool(LimitedTestCase):
|
|||||||
self.assertEqual(len(my_object), len(prox))
|
self.assertEqual(len(my_object), len(prox))
|
||||||
self.assertEqual(my_object.join(['a', 'b']), prox.join(['a', 'b']))
|
self.assertEqual(my_object.join(['a', 'b']), prox.join(['a', 'b']))
|
||||||
|
|
||||||
@skip_with_pyevent
|
@tests.skip_with_pyevent
|
||||||
def test_wrap_uniterable(self):
|
def test_wrap_uniterable(self):
|
||||||
prox = tpool.Proxy([])
|
prox = tpool.Proxy([])
|
||||||
|
|
||||||
@@ -76,7 +76,7 @@ class TestTpool(LimitedTestCase):
|
|||||||
self.assertRaises(IndexError, index)
|
self.assertRaises(IndexError, index)
|
||||||
self.assertRaises(TypeError, key)
|
self.assertRaises(TypeError, key)
|
||||||
|
|
||||||
@skip_with_pyevent
|
@tests.skip_with_pyevent
|
||||||
def test_wrap_dict(self):
|
def test_wrap_dict(self):
|
||||||
my_object = {'a': 1}
|
my_object = {'a': 1}
|
||||||
prox = tpool.Proxy(my_object)
|
prox = tpool.Proxy(my_object)
|
||||||
@@ -85,7 +85,7 @@ class TestTpool(LimitedTestCase):
|
|||||||
self.assertEqual(str(my_object), str(prox))
|
self.assertEqual(str(my_object), str(prox))
|
||||||
self.assertEqual(repr(my_object), repr(prox))
|
self.assertEqual(repr(my_object), repr(prox))
|
||||||
|
|
||||||
@skip_with_pyevent
|
@tests.skip_with_pyevent
|
||||||
def test_wrap_module_class(self):
|
def test_wrap_module_class(self):
|
||||||
prox = tpool.Proxy(re)
|
prox = tpool.Proxy(re)
|
||||||
self.assertEqual(tpool.Proxy, type(prox))
|
self.assertEqual(tpool.Proxy, type(prox))
|
||||||
@@ -93,7 +93,7 @@ class TestTpool(LimitedTestCase):
|
|||||||
self.assertEqual(exp.groups, 3)
|
self.assertEqual(exp.groups, 3)
|
||||||
assert repr(prox.compile)
|
assert repr(prox.compile)
|
||||||
|
|
||||||
@skip_with_pyevent
|
@tests.skip_with_pyevent
|
||||||
def test_wrap_eq(self):
|
def test_wrap_eq(self):
|
||||||
prox = tpool.Proxy(re)
|
prox = tpool.Proxy(re)
|
||||||
exp1 = prox.compile('.')
|
exp1 = prox.compile('.')
|
||||||
@@ -102,12 +102,12 @@ class TestTpool(LimitedTestCase):
|
|||||||
exp3 = prox.compile('/')
|
exp3 = prox.compile('/')
|
||||||
assert exp1 != exp3
|
assert exp1 != exp3
|
||||||
|
|
||||||
@skip_with_pyevent
|
@tests.skip_with_pyevent
|
||||||
def test_wrap_ints(self):
|
def test_wrap_ints(self):
|
||||||
p = tpool.Proxy(4)
|
p = tpool.Proxy(4)
|
||||||
assert p == 4
|
assert p == 4
|
||||||
|
|
||||||
@skip_with_pyevent
|
@tests.skip_with_pyevent
|
||||||
def test_wrap_hash(self):
|
def test_wrap_hash(self):
|
||||||
prox1 = tpool.Proxy('' + 'A')
|
prox1 = tpool.Proxy('' + 'A')
|
||||||
prox2 = tpool.Proxy('A' + '')
|
prox2 = tpool.Proxy('A' + '')
|
||||||
@@ -118,7 +118,7 @@ class TestTpool(LimitedTestCase):
|
|||||||
proxList = tpool.Proxy([])
|
proxList = tpool.Proxy([])
|
||||||
self.assertRaises(TypeError, hash, proxList)
|
self.assertRaises(TypeError, hash, proxList)
|
||||||
|
|
||||||
@skip_with_pyevent
|
@tests.skip_with_pyevent
|
||||||
def test_wrap_nonzero(self):
|
def test_wrap_nonzero(self):
|
||||||
prox = tpool.Proxy(re)
|
prox = tpool.Proxy(re)
|
||||||
exp1 = prox.compile('.')
|
exp1 = prox.compile('.')
|
||||||
@@ -126,7 +126,7 @@ class TestTpool(LimitedTestCase):
|
|||||||
prox2 = tpool.Proxy([1, 2, 3])
|
prox2 = tpool.Proxy([1, 2, 3])
|
||||||
assert bool(prox2)
|
assert bool(prox2)
|
||||||
|
|
||||||
@skip_with_pyevent
|
@tests.skip_with_pyevent
|
||||||
def test_multiple_wraps(self):
|
def test_multiple_wraps(self):
|
||||||
prox1 = tpool.Proxy(re)
|
prox1 = tpool.Proxy(re)
|
||||||
prox2 = tpool.Proxy(re)
|
prox2 = tpool.Proxy(re)
|
||||||
@@ -135,18 +135,18 @@ class TestTpool(LimitedTestCase):
|
|||||||
del x2
|
del x2
|
||||||
prox2.compile('.')
|
prox2.compile('.')
|
||||||
|
|
||||||
@skip_with_pyevent
|
@tests.skip_with_pyevent
|
||||||
def test_wrap_getitem(self):
|
def test_wrap_getitem(self):
|
||||||
prox = tpool.Proxy([0, 1, 2])
|
prox = tpool.Proxy([0, 1, 2])
|
||||||
self.assertEqual(prox[0], 0)
|
self.assertEqual(prox[0], 0)
|
||||||
|
|
||||||
@skip_with_pyevent
|
@tests.skip_with_pyevent
|
||||||
def test_wrap_setitem(self):
|
def test_wrap_setitem(self):
|
||||||
prox = tpool.Proxy([0, 1, 2])
|
prox = tpool.Proxy([0, 1, 2])
|
||||||
prox[1] = 2
|
prox[1] = 2
|
||||||
self.assertEqual(prox[1], 2)
|
self.assertEqual(prox[1], 2)
|
||||||
|
|
||||||
@skip_with_pyevent
|
@tests.skip_with_pyevent
|
||||||
def test_wrap_iterator(self):
|
def test_wrap_iterator(self):
|
||||||
self.reset_timeout(2)
|
self.reset_timeout(2)
|
||||||
prox = tpool.Proxy(range(10))
|
prox = tpool.Proxy(range(10))
|
||||||
@@ -155,7 +155,7 @@ class TestTpool(LimitedTestCase):
|
|||||||
result.append(i)
|
result.append(i)
|
||||||
self.assertEqual(list(range(10)), result)
|
self.assertEqual(list(range(10)), result)
|
||||||
|
|
||||||
@skip_with_pyevent
|
@tests.skip_with_pyevent
|
||||||
def test_wrap_iterator2(self):
|
def test_wrap_iterator2(self):
|
||||||
self.reset_timeout(5) # might take a while due to imprecise sleeping
|
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]
|
assert counter[0] > 10, counter[0]
|
||||||
gt.kill()
|
gt.kill()
|
||||||
|
|
||||||
@skip_with_pyevent
|
@tests.skip_with_pyevent
|
||||||
def test_raising_exceptions(self):
|
def test_raising_exceptions(self):
|
||||||
prox = tpool.Proxy(re)
|
prox = tpool.Proxy(re)
|
||||||
|
|
||||||
@@ -196,7 +196,7 @@ class TestTpool(LimitedTestCase):
|
|||||||
prox = tpool.Proxy(tpool_test)
|
prox = tpool.Proxy(tpool_test)
|
||||||
self.assertRaises(RuntimeError, prox.raise_exception)
|
self.assertRaises(RuntimeError, prox.raise_exception)
|
||||||
|
|
||||||
@skip_with_pyevent
|
@tests.skip_with_pyevent
|
||||||
def test_variable_and_keyword_arguments_with_function_calls(self):
|
def test_variable_and_keyword_arguments_with_function_calls(self):
|
||||||
import optparse
|
import optparse
|
||||||
parser = tpool.Proxy(optparse.OptionParser())
|
parser = tpool.Proxy(optparse.OptionParser())
|
||||||
@@ -204,7 +204,7 @@ class TestTpool(LimitedTestCase):
|
|||||||
opts, args = parser.parse_args(["-nfoo"])
|
opts, args = parser.parse_args(["-nfoo"])
|
||||||
self.assertEqual(opts.n, 'foo')
|
self.assertEqual(opts.n, 'foo')
|
||||||
|
|
||||||
@skip_with_pyevent
|
@tests.skip_with_pyevent
|
||||||
def test_contention(self):
|
def test_contention(self):
|
||||||
from tests import tpool_test
|
from tests import tpool_test
|
||||||
prox = tpool.Proxy(tpool_test)
|
prox = tpool.Proxy(tpool_test)
|
||||||
@@ -216,19 +216,19 @@ class TestTpool(LimitedTestCase):
|
|||||||
results = list(pile)
|
results = list(pile)
|
||||||
self.assertEqual(len(results), 3)
|
self.assertEqual(len(results), 3)
|
||||||
|
|
||||||
@skip_with_pyevent
|
@tests.skip_with_pyevent
|
||||||
def test_timeout(self):
|
def test_timeout(self):
|
||||||
import time
|
import time
|
||||||
eventlet.Timeout(0.1, eventlet.TimeoutError())
|
eventlet.Timeout(0.1, eventlet.TimeoutError())
|
||||||
self.assertRaises(eventlet.TimeoutError,
|
self.assertRaises(eventlet.TimeoutError,
|
||||||
tpool.execute, time.sleep, 0.3)
|
tpool.execute, time.sleep, 0.3)
|
||||||
|
|
||||||
@skip_with_pyevent
|
@tests.skip_with_pyevent
|
||||||
def test_killall(self):
|
def test_killall(self):
|
||||||
tpool.killall()
|
tpool.killall()
|
||||||
tpool.setup()
|
tpool.setup()
|
||||||
|
|
||||||
@skip_with_pyevent
|
@tests.skip_with_pyevent
|
||||||
def test_killall_remaining_results(self):
|
def test_killall_remaining_results(self):
|
||||||
semaphore = event.Event()
|
semaphore = event.Event()
|
||||||
|
|
||||||
@@ -244,7 +244,7 @@ class TestTpool(LimitedTestCase):
|
|||||||
tpool.killall()
|
tpool.killall()
|
||||||
gt.wait()
|
gt.wait()
|
||||||
|
|
||||||
@skip_with_pyevent
|
@tests.skip_with_pyevent
|
||||||
def test_autowrap(self):
|
def test_autowrap(self):
|
||||||
x = tpool.Proxy({'a': 1, 'b': 2}, autowrap=(int,))
|
x = tpool.Proxy({'a': 1, 'b': 2}, autowrap=(int,))
|
||||||
assert isinstance(x.get('a'), tpool.Proxy)
|
assert isinstance(x.get('a'), tpool.Proxy)
|
||||||
@@ -255,7 +255,7 @@ class TestTpool(LimitedTestCase):
|
|||||||
assert isinstance(x.one, tpool.Proxy)
|
assert isinstance(x.one, tpool.Proxy)
|
||||||
assert not isinstance(x.none, tpool.Proxy)
|
assert not isinstance(x.none, tpool.Proxy)
|
||||||
|
|
||||||
@skip_with_pyevent
|
@tests.skip_with_pyevent
|
||||||
def test_autowrap_names(self):
|
def test_autowrap_names(self):
|
||||||
x = tpool.Proxy({'a': 1, 'b': 2}, autowrap_names=('get',))
|
x = tpool.Proxy({'a': 1, 'b': 2}, autowrap_names=('get',))
|
||||||
assert isinstance(x.get('a'), tpool.Proxy)
|
assert isinstance(x.get('a'), tpool.Proxy)
|
||||||
@@ -265,7 +265,7 @@ class TestTpool(LimitedTestCase):
|
|||||||
assert isinstance(x.one, tpool.Proxy)
|
assert isinstance(x.one, tpool.Proxy)
|
||||||
assert not isinstance(x.two, tpool.Proxy)
|
assert not isinstance(x.two, tpool.Proxy)
|
||||||
|
|
||||||
@skip_with_pyevent
|
@tests.skip_with_pyevent
|
||||||
def test_autowrap_both(self):
|
def test_autowrap_both(self):
|
||||||
from tests import tpool_test
|
from tests import tpool_test
|
||||||
x = tpool.Proxy(tpool_test, autowrap=(int,), autowrap_names=('one',))
|
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
|
# violating the abstraction to check that we didn't double-wrap
|
||||||
assert not isinstance(x._obj, tpool.Proxy)
|
assert not isinstance(x._obj, tpool.Proxy)
|
||||||
|
|
||||||
@skip_with_pyevent
|
@tests.skip_with_pyevent
|
||||||
def test_callable(self):
|
def test_callable(self):
|
||||||
def wrapped(arg):
|
def wrapped(arg):
|
||||||
return arg
|
return arg
|
||||||
@@ -284,7 +284,7 @@ class TestTpool(LimitedTestCase):
|
|||||||
assert isinstance(x(4), tpool.Proxy)
|
assert isinstance(x(4), tpool.Proxy)
|
||||||
self.assertEqual("4", str(x(4)))
|
self.assertEqual("4", str(x(4)))
|
||||||
|
|
||||||
@skip_with_pyevent
|
@tests.skip_with_pyevent
|
||||||
def test_callable_iterator(self):
|
def test_callable_iterator(self):
|
||||||
def wrapped(arg):
|
def wrapped(arg):
|
||||||
yield arg
|
yield arg
|
||||||
@@ -295,22 +295,22 @@ class TestTpool(LimitedTestCase):
|
|||||||
for r in x(3):
|
for r in x(3):
|
||||||
self.assertEqual(3, r)
|
self.assertEqual(3, r)
|
||||||
|
|
||||||
@skip_with_pyevent
|
@tests.skip_with_pyevent
|
||||||
def test_eventlet_timeout(self):
|
def test_eventlet_timeout(self):
|
||||||
def raise_timeout():
|
def raise_timeout():
|
||||||
raise eventlet.Timeout()
|
raise eventlet.Timeout()
|
||||||
self.assertRaises(eventlet.Timeout, tpool.execute, raise_timeout)
|
self.assertRaises(eventlet.Timeout, tpool.execute, raise_timeout)
|
||||||
|
|
||||||
@skip_with_pyevent
|
@tests.skip_with_pyevent
|
||||||
def test_tpool_set_num_threads(self):
|
def test_tpool_set_num_threads(self):
|
||||||
tpool.set_num_threads(5)
|
tpool.set_num_threads(5)
|
||||||
self.assertEqual(5, tpool._nthreads)
|
self.assertEqual(5, tpool._nthreads)
|
||||||
|
|
||||||
|
|
||||||
class TpoolLongTests(LimitedTestCase):
|
class TpoolLongTests(tests.LimitedTestCase):
|
||||||
TEST_TIMEOUT = 60
|
TEST_TIMEOUT = 60
|
||||||
|
|
||||||
@skip_with_pyevent
|
@tests.skip_with_pyevent
|
||||||
def test_a_buncha_stuff(self):
|
def test_a_buncha_stuff(self):
|
||||||
assert_ = self.assert_
|
assert_ = self.assert_
|
||||||
|
|
||||||
@@ -339,7 +339,7 @@ class TpoolLongTests(LimitedTestCase):
|
|||||||
self.assertEqual(len(results), cnt)
|
self.assertEqual(len(results), cnt)
|
||||||
tpool.killall()
|
tpool.killall()
|
||||||
|
|
||||||
@skip_with_pyevent
|
@tests.skip_with_pyevent
|
||||||
def test_leakage_from_tracebacks(self):
|
def test_leakage_from_tracebacks(self):
|
||||||
tpool.execute(noop) # get it started
|
tpool.execute(noop) # get it started
|
||||||
gc.collect()
|
gc.collect()
|
||||||
@@ -362,5 +362,5 @@ class TpoolLongTests(LimitedTestCase):
|
|||||||
tpool.killall()
|
tpool.killall()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
def test_isolate_from_socket_default_timeout():
|
||||||
main()
|
tests.run_isolated('tpool_isolate_socket_default_timeout.py', timeout=1)
|
||||||
|
Reference in New Issue
Block a user