У меня есть модуль кэширования urllib2, который спорадически выходит из строя из-за следующего кода:
if not os.path.exists(self.cache_location):
os.mkdir(self.cache_location)
Проблема заключается в том, что к моменту выполнения второй строки папка может существовать и будет иметь ошибку:
File ".../cache.py", line 103, in __init__ os.mkdir(self.cache_location) OSError: [Errno 17] File exists: '/tmp/examplecachedir/'
Это связано с тем, что script одновременно запускается много раз, сторонним кодом у меня нет контроля.
Код (до того, как я попытался исправить ошибку) можно найти здесь, на github
Я не могу использовать tempfile.mkstemp, поскольку он решает условие гонки, используя случайно названный каталог (tempfile.py источник здесь), что приведет к поражению цели кеша.
Я не хочу просто отбрасывать ошибку, так как ошибка при ошибке Errno 17 возникает, если имя папки существует как файл (другая ошибка), например:
$ touch blah $ python >>> import os >>> os.mkdir("blah") Traceback (most recent call last): File "", line 1, in OSError: [Errno 17] File exists: 'blah' >>>
Я не могу использовать threading.RLock
, поскольку код вызывается из нескольких процессов.
Итак, я попробовал написать простую блокировку на основе файлов (эту версию можно найти здесь), но это имеет проблему: она создает файл блокировки на один уровень вверх, поэтому /tmp/example.lock
для /tmp/example/
, который прерывается, если вы используете /tmp/
в качестве кеша dir (поскольку он пытается сделать /tmp.lock
)..
Короче, мне нужно кэшировать ответы urllib2
на диск. Для этого мне нужно получить доступ к известному каталогу (создав его, если требуется), безопасным способом многопроцессорности. Он должен работать на OS X, Linux и Windows.
Мысли? Единственное альтернативное решение, о котором я могу думать, - это переписать модуль кэша с использованием хранилища SQLite3, а не файлов.