Skip to content

uvicorn reload fails on Windows and Python 3.8 #529

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

Closed
f0ff886f opened this issue Dec 18, 2019 · 9 comments · Fixed by #535
Closed

uvicorn reload fails on Windows and Python 3.8 #529

f0ff886f opened this issue Dec 18, 2019 · 9 comments · Fixed by #535

Comments

@f0ff886f
Copy link

I know this was referred to in #477 and #509 but it still isn't solved (making a new issue as I hijacked a closed one before).

Using uvicorn checked out 996aa2d, running with or without --loop asyncio changes nothing (that code was removed):

ERROR:    Accept failed on a socket
socket: <asyncio.TransportSocket fd=764, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=6, laddr=('127.0.0.1', 8000)>
Traceback (most recent call last):
  File "C:\Users\f\scoop\apps\python\current\lib\asyncio\proactor_events.py", line 817, in loop
    f = self._proactor.accept(sock)
  File "C:\Users\f\scoop\apps\python\current\lib\asyncio\windows_events.py", line 545, in accept
    self._register_with_iocp(listener)
  File "C:\Users\f\scoop\apps\python\current\lib\asyncio\windows_events.py", line 714, in _register_with_iocp
    _overlapped.CreateIoCompletionPort(obj.fileno(), self._iocp, 0, 0)
OSError: [WinError 87] The parameter is incorrect
Python 3.8.0 (tags/v3.8.0:fa919fd, Oct 14 2019, 19:37:50) [MSC v.1916 64 bit (AMD64)] on win32
@f0ff886f
Copy link
Author

This does not repro on py37, reloading works fine there.

Python 3.7.5 (tags/v3.7.5:5c02a39a0b, Oct 15 2019, 00:11:34) [MSC v.1916 64 bit (AMD64)] on win32

@f0ff886f f0ff886f changed the title uvicorn reload fails on Windows uvicorn reload fails on Windows and Python 3.8 Dec 19, 2019
@tomchristie
Copy link
Member

Right, so the problem here is to do with IOCP.

In Python 3.8 the default loop policy changes on Windows to use IOCP by default. We probably want to explcitly turn this off (and remove our loop="iocp" support completly, since it appears to not work.)

Does this only occur when using multiple workers / reload, or does it always occur on Python 3.8 with Windows?

@euri10
Copy link
Member

euri10 commented Dec 19, 2019

I can trigger the same on windows and 3.7.5
passing --loop="asyncio" is fine on 3.7.5
passing --loop="asyncio" on 3.8.0 the bug still here

@f0ff886f
Copy link
Author

Does this only occur when using multiple workers / reload, or does it always occur on Python 3.8 with Windows?

I'm not sure I understand the question. If I launch uvicorn with --reload and just use it (without changing code), it works OK with no errors. As soon as the reload is requested all hell breaks loose.

@euri10
Copy link
Member

euri10 commented Dec 19, 2019

feels like it's more about the way sockets are passed around in child processes since it happens also on asyncio loop and only with reload
sorry cant trigger on 3.7.5

@euri10
Copy link
Member

euri10 commented Dec 19, 2019

summary:
3.7.5
no bug with
C:/Users/benoi/.virtualenvs/uvicorn/Scripts/uvicorn-script.py toto:app --reload
C:/Users/benoi/.virtualenvs/uvicorn/Scripts/uvicorn-script.py toto:app --reload --loop=asyncio
bug with
C:/Users/benoi/.virtualenvs/uvicorn/Scripts/uvicorn-script.py toto:app --reload --loop=iocp

3.8
bug with all
C:/Users/benoi/.virtualenvs/uvicorn3.8/Scripts/uvicorn-script.py toto:app --reload
C:/Users/benoi/.virtualenvs/uvicorn3.8/Scripts/uvicorn-script.py toto:app --reload --loop=asyncio
C:/Users/benoi/.virtualenvs/uvicorn3.8/Scripts/uvicorn-script.py toto:app --reload --loop=iocp

@euri10
Copy link
Member

euri10 commented Dec 20, 2019

note also that

if platform.system() == "Windows":
from multiprocessing.resource_sharer import DupSocket
sockets = [DupSocket(s) for s in sockets]

and
if platform.system() == "Windows":
sockets = [s.detach() for s in sockets]

can be replaced by multiprocessing.allow_connection_pickling() which doesnt solve the 3.8 bug but simplifies things

@tomchristie
Copy link
Member

3.8 - bug with all

Indeed. The problem is that loop=asyncio will use the default loop policy for asyncio.
On windows that's IOCP under 3.8, which appears to have issues with sharing sockets between processes.

To resolve this we should:

@euri10 euri10 mentioned this issue Dec 20, 2019
@euri10
Copy link
Member

euri10 commented Dec 20, 2019

seems like that did the trick

C:\Users\benoi\.virtualenvs\uvicorn3.8\Scripts\python.exe C:/Users/benoi/.virtualenvs/uvicorn3.8/Scripts/uvicorn-script.py toto:app --reload --log-level=debug
INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO:     Started reloader process [6740]
DEBUG:    Using selector: SelectSelector
INFO:     Started server process [8380]
INFO:     <Server sockets=(<asyncio.TransportSocket fd=712, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=6, laddr=('127.0.0.1', 8000)>,)> is serving
INFO:     Waiting for application startup.
INFO:     ASGI 'lifespan' protocol appears unsupported.
INFO:     Application startup complete.
WARNING:  Detected file change in 'toto.py'. Reloading...
DEBUG:    Using selector: SelectSelector
INFO:     Started server process [2684]
INFO:     <Server sockets=(<asyncio.TransportSocket fd=540, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=6, laddr=('127.0.0.1', 8000)>,)> is serving
INFO:     Waiting for application startup.
INFO:     ASGI 'lifespan' protocol appears unsupported.
INFO:     Application startup complete.

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

Successfully merging a pull request may close this issue.

3 participants