Os.getcwd() вызывает исключение на сервере django dev
У меня есть проект django, запущенный в docker, и сервис работает с командой python manage.py runserver
, с открытой автозагрузкой файлов и использованием потоков.
Мой код вызывает shutil.make_archive()
, который затем вызывает os.getcwd()
, и время от времени os.getcwd()
вызывает FileNotFoundError
, при поиске дополнительной информации, теперь я понял, что ошибка может быть вызвана тем, что путь больше не существует, потому что путь удаляется где-то еще после того, как я ввожу путь.
Ошибка возникает только иногда, и я не смог найти стабильный способ воспроизвести ее, как только это происходит, я могу устранить проблему, внеся изменения в код, чтобы вызвать автозагрузку файла или перезапустить службу docker, похоже, убедитесь, что перезапуск процесса поможет, иначе ошибка продолжает возникать.
Когда все идет правильно, os.getcwd()
вернет путь к корневому dir моего проекта django.
И я на 100% уверен, что мой код не делает ничего связанного с манипуляциями с dir, как os.chdir()
.
В двух словах, сервер django работает нормально, вдруг os.getcwd()
начинает выдавать ошибку, пока я не перезапущу процесс.
Мой вопрос в том, что может быть основной причиной? Возможно ли, что python manage.py runserver
может вызвать какую-либо проблему?
Python: v3.8.6
Django: v3.2
Docker: v20.10.12
Оказалось, что это не имеет никакого отношения к dev-серверу или docker.
Это происходит потому, что shutil.make_archive
не является потокобезопасным.
Что делает shutil.make_archive
:
- вызов os.getcwd() для сохранения текущего пути к dir
- os.chdir в любой нужный ему каталог
- выполнить процесс архивирования
- os.chdir обратно в каталог, сохраненный на первом этапе (аналогично выполнению
pushd .; popd;
)
Я вызываю shutil.make_archive
одновременно из нескольких потоков, а также rmdir этих temp dirs, и поскольку os.chdir
вступает в силу в зависимости от процесса, то все происходит в следующем порядке:
- os.chdir(dir_path)
- os.rmdir(dir_path)
- os.getcwd()
и на последнем шаге FileNotFoundError
поднимается благодаря условию гонки.
Для тех, кто хочет больше узнать о потокобезопасности shutil.make_archive
, есть thread, посвященный этому.