tornado icon indicating copy to clipboard operation
tornado copied to clipboard

"tornado.curl_httpclient.CurlError: HTTP 599: Failed writing header" after updating to python 3.10 on alpine 3.15

Open ghevge opened this issue 3 years ago • 1 comments

Hi, Recently I've updated my tornado tests container to python:3.10-alpine3.15 from python:3.9.6-alpine3.14. After doing this, my tests started to fail with the error below.

These are my dependencies:

coverage==5.3
pytest==6.2.4
pytest-cov==2.10.1
pytest-rerunfailures==10.1
redislite==5.0.142319
pytest-mock==3.6.1
pytest-tornado==0.8.1
ptvsd==4.2.7
pytest-xdist==2.3.0
aiohttp==3.7.4.post0
SQLAlchemy==1.4.22
Deprecated==1.2.11
nest-asyncio==1.5.1
ldap3==2.7
tornado==6.1
alembic==1.6.5
psycopg2==2.9.1
asyncpg==0.23.0
pycurl==7.43.0
cookies==2.2.1
opuslib==3.0.1
redis==3.3.8
apispec==3.3.1
apispec-webframeworks==0.5.2
marshmallow==3.7.0
itsdangerous==1.1.0
sendgrid==5.6.0
grpcio-tools==1.38.1
protoc-gen-swagger==0.1.0
googleapis-common-protos==1.6.0
prometheus_client==0.7.1
jaeger-client==4.3.0
python-dateutil==2.8.1

Any idea what could cause this errors?

Thanks

tests/admin/handlers/data_collection/data_collection_test.py:233: in _create_task
    response = self._fetch(TASKS_URI, body=json.dumps(task), method='POST')
tests/base.py:608: in _fetch
    return self.fetch(*args, **kwargs)
/usr/local/lib/python3.10/site-packages/tornado/testing.py:443: in fetch
    return self.io_loop.run_sync(
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <tornado.platform.asyncio.AsyncIOLoop object at 0x7f43438c2ef0>, func = <function AsyncHTTPTestCase.fetch.<locals>.<lambda> at 0x7f43437497e0>, timeout = 300.0

    def run_sync(self, func: Callable, timeout: Optional[float] = None) -> Any:
        """Starts the `IOLoop`, runs the given function, and stops the loop.
    
        The function must return either an awaitable object or
        ``None``. If the function returns an awaitable object, the
        `IOLoop` will run until the awaitable is resolved (and
        `run_sync()` will return the awaitable's result). If it raises
        an exception, the `IOLoop` will stop and the exception will be
        re-raised to the caller.
    
        The keyword-only argument ``timeout`` may be used to set
        a maximum duration for the function.  If the timeout expires,
        a `tornado.util.TimeoutError` is raised.
    
        This method is useful to allow asynchronous calls in a
        ``main()`` function::
    
            async def main():
                # do stuff...
    
            if __name__ == '__main__':
                IOLoop.current().run_sync(main)
    
        .. versionchanged:: 4.3
           Returning a non-``None``, non-awaitable value is now an error.
    
        .. versionchanged:: 5.0
           If a timeout occurs, the ``func`` coroutine will be cancelled.
    
        """
        future_cell = [None]  # type: List[Optional[Future]]
    
        def run() -> None:
            try:
                result = func()
                if result is not None:
                    from tornado.gen import convert_yielded
    
                    result = convert_yielded(result)
            except Exception:
                fut = Future()  # type: Future[Any]
                future_cell[0] = fut
                future_set_exc_info(fut, sys.exc_info())
            else:
                if is_future(result):
                    future_cell[0] = result
                else:
                    fut = Future()
                    future_cell[0] = fut
                    fut.set_result(result)
            assert future_cell[0] is not None
            self.add_future(future_cell[0], lambda future: self.stop())
    
        self.add_callback(run)
        if timeout is not None:
    
            def timeout_callback() -> None:
                # If we can cancel the future, do so and wait on it. If not,
                # Just stop the loop and return with the task still pending.
                # (If we neither cancel nor wait for the task, a warning
                # will be logged).
                assert future_cell[0] is not None
                if not future_cell[0].cancel():
                    self.stop()
    
            timeout_handle = self.add_timeout(self.time() + timeout, timeout_callback)
        self.start()
        if timeout is not None:
            self.remove_timeout(timeout_handle)
        assert future_cell[0] is not None
        if future_cell[0].cancelled() or not future_cell[0].done():
            raise TimeoutError("Operation timed out after %s seconds" % timeout)
>       return future_cell[0].result()
E       tornado.curl_httpclient.CurlError: HTTP 599: Failed writing header

/usr/local/lib/python3.10/site-packages/tornado/ioloop.py:530: CurlError

ghevge avatar Dec 13 '21 18:12 ghevge

I have no idea what might be causing this, but I noticed nest-asyncio in your dependencies list, and I'm suspicious of that package. Nesting asyncio event loops in the wrong places could cause all kinds of undefined behavior.

bdarnell avatar Jan 29 '22 20:01 bdarnell