Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IOLoop._instance is never set, causing hanging callbacks on multi-threaded tests #27

Open
wouterdb opened this issue Dec 2, 2017 · 1 comment

Comments

@wouterdb
Copy link

wouterdb commented Dec 2, 2017

I noticed a subtle problem when using IOLoop.current(instance=True) in multi-threaded applications when using pytest-tornado:

If tornado starts the first IOLoop (on the main thread) it sets IOLoop._instance to point to this IOLoop
However, the fixture never sets this field.

When calling IOLoop.current(instance=True) on any thread except for the thread in which the pytest-tornado ioloop fixture is executed, it will not find a current IOLoop for that thread and fall back to the global IOLoop._instance . If this field is absent, IOLoop assumes this is the first attempt to get an IOLoop and create a new IOLoop and set it as IOLoop._instance.

As such, all calls to IOLoop.current(instance=True) from other threads will get this IOLoop instance, which has not been started. All calls scheduled on that IOLoop will hang, causing tests to timeout.

Setting IOLoop._instance before the test and removing it afterwards resolves the issue.

(I hope my description is clear).

@yen3
Copy link

yen3 commented Jan 9, 2018

I meet one problem. When I try to call tornado.process.Subprocess.wait_for_exit() function, the pytest-tornado will hang. I don't the problem is like what @wouterdb mentioned or not.

The test code is as the following:

from tornado import gen
from tornado.process import Subprocess

import pytest

@gen.coroutine
def echo_hello_world():
    return_code = yield Subprocess(args=["echo", "hello", "world"]).wait_for_exit()

    return return_code

@pytest.mark.gen_test
def test_cmd_1():
    yield echo_hello_world()

@pytest.mark.gen_test
def test_cmd_2():
    yield echo_hello_world()

The test will hang in test_cmd_2

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants