question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

uvicorn.run with reload or workers in ProcessPoolExecutor fails with Bad file descriptor error

See original GitHub issue

Greetings!

I have run into an issue when trying to spawn several local uvicorns (obviously bound to different ports) from within Python. Instead of launching each one manually in a separate terminal, I have set up a function that spawns the desired servers in a ProcessPoolExecutor (imported from concurrent.futures). However, if the servers are configured with the workers or reload options, I get the following error:

    Process SpawnProcess-1:1:
    Traceback (most recent call last):
      File "/usr/lib/python3.8/multiprocessing/process.py", line 315, in _bootstrap
        self.run()
      File "/usr/lib/python3.8/multiprocessing/process.py", line 108, in run
        self._target(*self._args, **self._kwargs)
      File "/home/cantor/code/envs/tabula/lib/python3.8/site-packages/uvicorn/subprocess.py", line 55, in subprocess_started
        sys.stdin = os.fdopen(stdin_fileno)
      File "/usr/lib/python3.8/os.py", line 1023, in fdopen
        return io.open(fd, *args, **kwargs)
    OSError: [Errno 9] Bad file descriptor

Stating the obvious, there is an issue with reopening stdin in the child process.

Simple workarounds resulting in happy server spawning:

  • Commenting out lines 54 and 55 in subprocess.py
    # if stdin_fileno is not None:
        # sys.stdin = os.fdopen(stdin_fileno)
  • Setting 'stdin_fileno': None on line 35 in subprocess.py

To reproduce

pip install fastapi uvicorn

(Assuming the code is located in launch.py)

With workers:

    import uvicorn
    from fastapi import FastAPI
    from concurrent.futures import ProcessPoolExecutor

    app = FastAPI()

    if __name__ == '__main__':

        with ProcessPoolExecutor() as executor:

            executor.submit(uvicorn.run, 'launch:app', workers = 3)

Error:

    Process SpawnProcess-1:3:
    Traceback (most recent call last):
    File "/usr/lib/python3.8/multiprocessing/process.py", line 315, in _bootstrap
        self.run()
    File "/usr/lib/python3.8/multiprocessing/process.py", line 108, in run
        self._target(*self._args, **self._kwargs)
    File "/usr/lib/python3.8/site-packages/uvicorn/subprocess.py", line 55, in subprocess_started
        sys.stdin = os.fdopen(stdin_fileno)
    File "/usr/lib/python3.8/os.py", line 1023, in fdopen
        return io.open(fd, *args, **kwargs)
    OSError: [Errno 9] Bad file descriptor
    Process SpawnProcess-1:1:
    Traceback (most recent call last):
    File "/usr/lib/python3.8/multiprocessing/process.py", line 315, in _bootstrap
        self.run()
    File "/usr/lib/python3.8/multiprocessing/process.py", line 108, in run
        self._target(*self._args, **self._kwargs)
    File "/usr/lib/python3.8/site-packages/uvicorn/subprocess.py", line 55, in subprocess_started
        sys.stdin = os.fdopen(stdin_fileno)
    File "/usr/lib/python3.8/os.py", line 1023, in fdopen
        return io.open(fd, *args, **kwargs)
    OSError: [Errno 9] Bad file descriptor
    Process SpawnProcess-1:2:
    Traceback (most recent call last):
    File "/usr/lib/python3.8/multiprocessing/process.py", line 315, in _bootstrap
        self.run()
    File "/usr/lib/python3.8/multiprocessing/process.py", line 108, in run
        self._target(*self._args, **self._kwargs)
    File "/usr/lib/python3.8/site-packages/uvicorn/subprocess.py", line 55, in subprocess_started
        sys.stdin = os.fdopen(stdin_fileno)
    File "/usr/lib/python3.8/os.py", line 1023, in fdopen
        return io.open(fd, *args, **kwargs)
    OSError: [Errno 9] Bad file descriptor

With reload:

    import uvicorn
    from fastapi import FastAPI
    from concurrent.futures import ProcessPoolExecutor

    app = FastAPI()

    if __name__ == '__main__':

        with ProcessPoolExecutor() as executor:

            executor.submit(uvicorn.run, 'launch:app', reload = True)

Error:

    Process SpawnProcess-1:1:
    Traceback (most recent call last):
    File "/usr/lib/python3.8/multiprocessing/process.py", line 315, in _bootstrap
        self.run()
    File "/usr/lib/python3.8/multiprocessing/process.py", line 108, in run
        self._target(*self._args, **self._kwargs)
    File "/usr/lib/python3.8/site-packages/uvicorn/subprocess.py", line 55, in subprocess_started
        sys.stdin = os.fdopen(stdin_fileno)
    File "/usr/lib/python3.8/os.py", line 1023, in fdopen
        return io.open(fd, *args, **kwargs)
    OSError: [Errno 9] Bad file descriptor

With 'stdin_fileno': None on line 35 in subprocess.py:

INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO:     Started reloader process [705451] using statreload
INFO:     Started server process [705462]
INFO:     Waiting for application startup.
INFO:     Application startup complete.

Expected behavior

uvicorn server starting normally with a reloader or one or more workers.

Actual behavior

Server runs, but no reloader or worker subprocesses.

Environment

  • OS: Ubuntu 20.04
  • Python: CPython 3.8.6
  • Uvicorn version: 0.12.3

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:9 (5 by maintainers)

github_iconTop GitHub Comments

1reaction
euri10commented, Dec 10, 2020

In summary, I’d say that a try/except is perfectly acceptable here (although I’d also argue that reopening stdin is not even necessary, but I’d be happy to stand corrected on that). I would gladly create a PR for this, but before that someone with a higher level of authority should decide what the solution should look like - a try/except, open('/dev/stdin') (probably inside a try/except) or just remove lines 26 -- 29, 35,54 and 55 altogether if those parts do not work as originally intended.

ping @blueyed, maybe you have insights on this !

the original commit seems specifically tied to pdb, which I never use and have very little experience on

on top of that it was written before we changed the default multiprocessing context to be the spawn context which is not the linux default, so maybe the interaction is different than with a plain forked process,

I’d say @likeanaxon send a PR on this the way you think it should work, then we’ll advise !

0reactions
euri10commented, Apr 22, 2022

the use case wont likely be supported, reload uses multiprocess spawn under the hood so you’re essentially multiprocessing^2

Read more comments on GitHub >

github_iconTop Results From Across the Web

uvicorn.run with reload or workers in ProcessPoolExecutor ...
uvicorn.run with reload or workers in ProcessPoolExecutor fails with Bad file descriptor error.
Read more >
OSError: [Errno 9] Bad file descriptor #1877 - benoitc/gunicorn
I had a similar issue (FastAPI + uvicorn worker + gunicorn + supervisor). Gunicorn was unable to stop workers and I saw the...
Read more >
OSError: [Errno 9] Bad file descriptor when processing large ...
I'm using python 3.9 and in a uvicorn fastAPI script. Sometimes when I'm processing a large number of items, I get this error...
Read more >
Falcon Documentation - Read the Docs
You can run the ASGI version with uvicorn or any other ASGI server ... auto-restart workers when it detects a code change, and...
Read more >
Multiprocessing Failed -- Bad file descriptor - PyTorch Forums
Using the multiprocessing library 'spawn' start method, I get an error “[Errno 9] Bad file descriptor” when I try to start the process....
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found