Mam moduł buforowania urllib2, co sporadycznie rozbija się z następującego kodu:Race stan tworzenia folder Pythonie
if not os.path.exists(self.cache_location):
os.mkdir(self.cache_location)
Problem, zanim druga linia jest wykonana, może folder istnieje i będzie błąd:
File ".../cache.py", line 103, in __init__ os.mkdir(self.cache_location) OSError: [Errno 17] File exists: '/tmp/examplecachedir/'
Dzieje się tak, ponieważ skrypt jest jednocześnie uruchamiany wiele razy, przy użyciu kodu innej firmy, nad którym nie mam kontroli.
Kod (przed Starałem się usunąć błędu) można znaleźć here, on github
nie mogę użyć tempfile.mkstemp, ponieważ rozwiązuje sytuacji wyścigu przy użyciu losowo nazwie katalogu (tempfile.py source here), który pokonał cel pamięci podręcznej.
Nie chcę po prostu usunąć ten błąd, ponieważ tego samego błędu errno 17 Błąd jest podniesione, jeśli nazwa folderu istnieje jako plik (inny błąd), na przykład:
$ touch blah $ python >>> import os >>> os.mkdir("blah") Traceback (most recent call last): File "", line 1, in OSError: [Errno 17] File exists: 'blah' >>>
nie mogę przy użyciu threading.RLock
, ponieważ kod jest wywoływany z wielu procesów.
Tak, próbowałem pisać prostą blokadę na podstawie pliku (that version can be found here) A, ale to nie ma wątpliwości: to tworzy plik blokujący jeden poziom w górę, więc /tmp/example.lock
dla /tmp/example/
, który łamie jeśli używasz /tmp/
jako cache dir (jak próbuje uzyskać /tmp.lock
) ..
Krótko mówiąc, muszę buforować odpowiedzi urllib2
na dysku. Aby to zrobić, muszę uzyskać dostęp do znanego katalogu (jeśli jest to wymagane), w sposób bezpieczny dla wielu procesorów. Musi działać na OS X, Linux i Windows.
Myśli? Jedynym alternatywnym rozwiązaniem, które mogę wymyślić, jest przepisanie modułu pamięci podręcznej przy użyciu pamięci SQLite3, a nie plików.
Prawdopodobnie! Zastanowiłem się nad tym tak samo, jak przed ponownym przeczytaniem pytania, zanim je przesłałem. Zaimplementowałem to (http://github.com/dbr/tvdb_api/blob/468d9f816373b14ef3a483fca07e031b69fa62f9/cache.py#L103-114), i sprawi, że osoba, która zgłosiła błąd, przetestuje go wkrótce. – dbr
To wydaje się działać idealnie, dzięki! – dbr
@dbr: zauważ, że w linii 114, chcesz 'raise e', ponieważ jest to już instancja' OSError'. http://github.com/dbr/tvdb_api/blob/468d9f816373b14ef3a483fca07e031b69fa62f9/cache.py#L114 – nosklo