Состояние гонки os.makedir в одной теме? Как убедиться, что каталог создан, прежде чем продолжить - PullRequest
1 голос
/ 06 января 2020

У меня очень странное поведение os.makedir в flask приложении.

У меня есть конечная точка API для загрузки изображений. Каждое изображение должно быть сгруппировано в каталоги в зависимости от условий. Если каталог не существует, каталог должен быть создан.

Изначально у меня был такой код в моем приложении:

    # create needed dir if doesn't exist
    if not os.path.isdir(os.path.dirname(abs_path)):
        os.mkdir(os.path.dirname(abs_path))

    # create a file and save it into a needed place
    with open(abs_path, 'wb') as f:
        shutil.copyfileobj(fp, f)
        f.flush()

И в 90% случаев он прекрасно работает. Но когда в запросе было два файла, которые должны быть помещены в один каталог, а каталог еще не был создан, я получил это:

flask_1  |   File "/app/storage.py", line 101, in save_file
flask_1  |     os.mkdir(os.path.dirname(abs_path))
flask_1  | FileExistsError: [Errno 17] File exists: '/static/df273d04909e71beb8b63b4d1b1c0a969ee6fc15'

Он может быть воспроизведен локально с успехом 100% в flask режим отладки с 1 потоком. Кажется, это какой-то Linux / docker или какое-то состояние гонки кеша.

Затем я просто изменил код на этот:

if not os.path.isdir(os.path.dirname(abs_path)):
    try:
        os.mkdir(os.path.dirname(abs_path))
    except FileExistsError:
        # Another thread was already created the directory when
        # several simultaneous requests has come
        if os.path.isdir(os.path.dirname(abs_path)):
            pass
        else:
            raise

    # create a file and save it into a needed place
    with open(abs_path, 'wb') as f:
        shutil.copyfileobj(fp, f)
        f.flush()

И проблема исчезла.

Но у меня есть опасения по поводу использования этого кода в рабочей среде, поскольку очень странно, что одна и та же проверка дает разные результаты.

Как убедиться, что каталог действительно создан, прежде чем продолжить обработку первого запроса?

PS Файлы на месте, второй фрагмент кода на месте. С первым только первый файл в каталоге и ошибка на втором.

IE С первым фрагментом кода Flask считает, что все в порядке и продолжает

1 Ответ

0 голосов
/ 06 января 2020

os.makedirs принимает параметр exist_ok, что при True не вызовет ошибку, если каталог существует

os.makedirs(os.path.dirname(abs_path), exist_ok=True)
...