Bug: Litestar crashes on initialization with Python 3.12.4 and a read-only root filesystem
jakeintel opened this issue · 3 comments
Description
Litestar throws an exception when starting on a container with a readonly root filesystem and python 3.12.4.
With earlier versions of 3.12 it does not throw.
With a read/write filesystem is does not throw.
URL to code causing the issue
https://github.com/jakeintel/litestar_bug_demo
MCVE
The repo link above has a simple, 'working' example.
Basically,
- create a hello-world app.
- Build it into a docker container that starts with uvicorn
- start the container with --readonly
Steps to reproduce
1. clone https://github.com/jakeintel/litestar_bug_demo
2. docker build -t demo .
3. docker run --read-only -it --rm demo
Screenshots
No response
Logs
warnings.warn(f'directory "{self.secrets_path}" does not exist')
Process SyncManager-1:
Traceback (most recent call last):
File "/usr/local/lib/python3.12/multiprocessing/process.py", line 314, in _bootstrap
self.run()
File "/usr/local/lib/python3.12/multiprocessing/process.py", line 108, in run
self._target(*self._args, **self._kwargs)
File "/usr/local/lib/python3.12/multiprocessing/managers.py", line 591, in _run_server
server = cls._Server(registry, address, authkey, serializer)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/multiprocessing/managers.py", line 156, in __init__
self.listener = Listener(address=address, backlog=128)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/multiprocessing/connection.py", line 458, in __init__
address = address or arbitrary_address(family)
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/multiprocessing/connection.py", line 77, in arbitrary_address
return tempfile.mktemp(prefix='listener-', dir=util.get_temp_dir())
^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/multiprocessing/util.py", line 149, in get_temp_dir
tempdir = tempfile.mkdtemp(prefix='pymp-')
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/tempfile.py", line 373, in mkdtemp
prefix, suffix, dir, output_type = _sanitize_params(prefix, suffix, dir)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/tempfile.py", line 126, in _sanitize_params
dir = gettempdir()
^^^^^^^^^^^^
File "/usr/local/lib/python3.12/tempfile.py", line 315, in gettempdir
return _os.fsdecode(_gettempdir())
^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/tempfile.py", line 308, in _gettempdir
tempdir = _get_default_tempdir()
^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/tempfile.py", line 223, in _get_default_tempdir
raise FileNotFoundError(_errno.ENOENT,
FileNotFoundError: [Errno 2] No usable temporary directory found in ['/tmp', '/var/tmp', '/usr/tmp', '/application']
Traceback (most recent call last):
File "/usr/local/lib/python3.12/logging/config.py", line 581, in configure
handler = self.configure_handler(handlers[name])
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/logging/config.py", line 792, in configure_handler
proxy_queue = MM().Queue()
^^^^
File "/usr/local/lib/python3.12/multiprocessing/context.py", line 57, in Manager
m.start()
File "/usr/local/lib/python3.12/multiprocessing/managers.py", line 566, in start
self._address = reader.recv()
^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/multiprocessing/connection.py", line 250, in recv
buf = self._recv_bytes()
^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/multiprocessing/connection.py", line 430, in _recv_bytes
buf = self._recv(4)
^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/multiprocessing/connection.py", line 399, in _recv
raise EOFError
EOFError
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/usr/local/bin/uvicorn", line 8, in <module>
sys.exit(main())
^^^^^^
File "/usr/local/lib/python3.12/site-packages/click/core.py", line 1157, in __call__
return self.main(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/site-packages/click/core.py", line 1078, in main
rv = self.invoke(ctx)
^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/site-packages/click/core.py", line 1434, in invoke
return ctx.invoke(self.callback, **ctx.params)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/site-packages/click/core.py", line 783, in invoke
return __callback(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/site-packages/uvicorn/main.py", line 418, in main
run(
File "/usr/local/lib/python3.12/site-packages/uvicorn/main.py", line 587, in run
server.run()
File "/usr/local/lib/python3.12/site-packages/uvicorn/server.py", line 62, in run
return asyncio.run(self.serve(sockets=sockets))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/asyncio/runners.py", line 194, in run
return runner.run(main)
^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/asyncio/runners.py", line 118, in run
return self._loop.run_until_complete(task)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/asyncio/base_events.py", line 687, in run_until_complete
return future.result()
^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/site-packages/uvicorn/server.py", line 69, in serve
config.load()
File "/usr/local/lib/python3.12/site-packages/uvicorn/config.py", line 458, in load
self.loaded_app = import_from_string(self.app)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/site-packages/uvicorn/importer.py", line 21, in import_from_string
module = importlib.import_module(module_str)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/importlib/__init__.py", line 90, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "<frozen importlib._bootstrap>", line 1387, in _gcd_import
File "<frozen importlib._bootstrap>", line 1360, in _find_and_load
File "<frozen importlib._bootstrap>", line 1331, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 935, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 995, in exec_module
File "<frozen importlib._bootstrap>", line 488, in _call_with_frames_removed
File "/application/api/app.py", line 42, in <module>
app = create_app()
^^^^^^^^^^^^
File "/application/api/app_factory.py", line 89, in create_app
return Litestar(
^^^^^^^^^
File "/usr/local/lib/python3.12/site-packages/litestar/app.py", line 487, in __init__
self.get_logger = self.logging_config.configure()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/site-packages/litestar/logging/config.py", line 276, in configure
config.dictConfig(values)
File "/usr/local/lib/python3.12/logging/config.py", line 920, in dictConfig
dictConfigClass(config).configure()
File "/usr/local/lib/python3.12/logging/config.py", line 588, in configure
raise ValueError('Unable to configure handler '
ValueError: Unable to configure handler 'queue_listener'
Litestar Version
I tried the following
- 2.9.1 (this is in the repo above)
- 2.9.0
- 2.8.3
Platform
- Linux
- Mac
- Windows
- Other (Please specify in the description above)
Note
While we are open for sponsoring on GitHub Sponsors and
OpenCollective, we also utilize Polar.sh to engage in pledge-based sponsorship.
Check out all issues funded or available for funding on our Polar.sh dashboard
- If you would like to see an issue prioritized, make a pledge towards it!
- We receive the pledge once the issue is completed & verified
- This, along with engagement in the community, helps us know which features are a priority to our users.
Hey @jakeintel, thanks for reporting this!
I'm not really sure if this classifies as a Litestar bug, and I believe it might be a bug in the 3.12.4 release, caused by the changes introduced in this PR: python/cpython#93269
It can be reproduced with this simple test setup. When you run this on a read-only FS, you'll get the exception:
import logging.config
logging.config.dictConfig(
{
"version": 1,
"handlers": {
"queue_listener": {
"class": "logging.handlers.QueueHandler",
"queue": {"()": "queue.Queue", "maxsize": -1},
},
},
}
)
@jakeintel I've filed a bug report at the CPython repo for this: python/cpython#120868