Commit 134f26bf authored by Jason Madden's avatar Jason Madden

Make the BackdoorServer kill its spawned greenlets when it is stopped.

Hopefully this will help diagnose the timeout error seen (only) on
Appveyor: The test that runs after test_multi hangs; all the other tests
work. (This was verified by changing the name of test_multi and thus its
sort order; the test after it is the one that fails.)
parent e6a45fb4
...@@ -141,8 +141,11 @@ Other Changes ...@@ -141,8 +141,11 @@ Other Changes
each other. **Note:** Writing to the *io* property of a FileObject should be each other. **Note:** Writing to the *io* property of a FileObject should be
considered deprecated. considered deprecated.
- Timeout exceptions (and other asynchronous exceptions) could cause - Timeout exceptions (and other asynchronous exceptions) could cause
the Backdoor server to fail to properly manage the the BackdoorServer to fail to properly manage the
stdout/stderr/stdin values. Reported with a patch in :pr:`874` by stefanmh. stdout/stderr/stdin values. Reported with a patch in :pr:`874` by
stefanmh.
- The BackDoorServer now tracks spawned greenlets (connections) and
kills them in its ``stop`` method.
Servers Servers
~~~~~~~ ~~~~~~~
......
...@@ -16,6 +16,7 @@ from code import InteractiveConsole ...@@ -16,6 +16,7 @@ from code import InteractiveConsole
from gevent.greenlet import Greenlet from gevent.greenlet import Greenlet
from gevent.hub import getcurrent from gevent.hub import getcurrent
from gevent.server import StreamServer from gevent.server import StreamServer
from gevent.pool import Pool
__all__ = ['BackdoorServer'] __all__ = ['BackdoorServer']
...@@ -88,6 +89,10 @@ class BackdoorServer(StreamServer): ...@@ -88,6 +89,10 @@ class BackdoorServer(StreamServer):
Hello from gevent backdoor! Hello from gevent backdoor!
>> print(foo) >> print(foo)
From defined scope! From defined scope!
.. versionchanged:: 1.2a1
Spawned greenlets are now tracked in a pool and killed when the server
is stopped.
""" """
def __init__(self, listener, locals=None, banner=None, **server_args): def __init__(self, listener, locals=None, banner=None, **server_args):
...@@ -96,7 +101,8 @@ class BackdoorServer(StreamServer): ...@@ -96,7 +101,8 @@ class BackdoorServer(StreamServer):
at the top-level. at the top-level.
:keyword banner: If geven, a string that will be printed to each connecting user. :keyword banner: If geven, a string that will be printed to each connecting user.
""" """
StreamServer.__init__(self, listener, spawn=_Greenlet_stdreplace.spawn, **server_args) group = Pool(greenlet_class=_Greenlet_stdreplace) # no limit on number
StreamServer.__init__(self, listener, spawn=group, **server_args)
_locals = {'__doc__': None, '__name__': '__console__'} _locals = {'__doc__': None, '__name__': '__console__'}
if locals: if locals:
_locals.update(locals) _locals.update(locals)
......
from __future__ import print_function
import greentest import greentest
import gevent import gevent
from gevent import socket from gevent import socket
from gevent import backdoor from gevent import backdoor
from _six import xrange
def read_until(conn, postfix): def read_until(conn, postfix):
read = b'' read = b''
...@@ -30,6 +29,7 @@ class Test(greentest.TestCase): ...@@ -30,6 +29,7 @@ class Test(greentest.TestCase):
def tearDown(self): def tearDown(self):
self._server.stop() self._server.stop()
self._server = None self._server = None
gevent.sleep() # let spawned greenlets die
super(Test, self).tearDown() super(Test, self).tearDown()
def _make_server(self, *args, **kwargs): def _make_server(self, *args, **kwargs):
...@@ -48,25 +48,29 @@ class Test(greentest.TestCase): ...@@ -48,25 +48,29 @@ class Test(greentest.TestCase):
line = readline(conn) line = readline(conn)
self.assertEqual(line, '') self.assertEqual(line, '')
conn.close() conn.close()
self.close_on_teardown.remove(conn)
def test_multi(self): def test_multi(self):
self._make_server() self._make_server()
def connect(): def connect():
conn = self._create_connection() conn = self._create_connection()
read_until(conn, '>>> ') read_until(conn, b'>>> ')
conn.sendall(b'2+2\r\n') conn.sendall(b'2+2\r\n')
line = readline(conn) line = readline(conn)
self.assertEqual(line.strip(), '4', repr(line)) self.assertEqual(line.strip(), '4', repr(line))
self._close(conn) self._close(conn)
jobs = [gevent.spawn(connect) for _ in xrange(10)] jobs = [gevent.spawn(connect) for _ in range(10)]
gevent.joinall(jobs, raise_error=True) done = gevent.joinall(jobs, raise_error=True)
self.assertEqual(len(done), len(jobs), done)
def test_quit(self): def test_quit(self):
self._make_server() self._make_server()
conn = self._create_connection() conn = self._create_connection()
read_until(conn, '>>> ') read_until(conn, b'>>> ')
self._close(conn) self._close(conn)
def test_sys_exit(self): def test_sys_exit(self):
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment