Rozwiązywanie problemów z operacjami wejścia-wyjścia i bezpiecznym anulowaniem w UnixLocal
Dlaczego operacje wejścia-wyjścia przestrzeni roboczej są problemem poprawności pętli zdarzeń
Pętla zdarzeń jest podstawowym elementem aplikacji asyncio. Uruchamia zadania asynchroniczne i wywołania zwrotne, operacje wejścia-wyjścia sieciowego oraz podprocesy. Dlatego sposób umieszczenia operacji przestrzeni roboczej ma znaczenie dla poprawności, gdy operacje te mogą wykonywać znaczącą pracę na systemie plików.
Implementacja UnixLocal obsługuje tę granicę, kierując wybrane operacje przestrzeni roboczej do wejścia-wyjścia wykonywanego przez proces roboczy, zamiast wykonywać całą pracę bezpośrednio w metodzie asynchronicznej.
Oś awarii: usuwanie rekurencyjne
Rekurencyjne usuwanie katalogu jest odrębną ścieżką operacji przestrzeni roboczej. Implementacja UnixLocal kieruje rekurencyjne usuwanie katalogu do procesu roboczego, zamiast wywoływać bezpośrednio shutil.rmtree w metodzie asynchronicznej.
Odpowiedni niezmiennik jest wąski: rekurencyjne usuwanie należy do ścieżki procesu roboczego. Różni się ona od ścieżek archiwizacji i rozpakowywania, które wykonują własne synchroniczne operacje na systemie plików.
Oś awarii: archiwizacja
Archiwizacja przestrzeni roboczej jest kolejną odrębną ścieżką. Implementacja UnixLocal wykonuje archiwizację przestrzeni roboczej w procesie roboczym, opakowując tarfile.open i tar.add w synchroniczną funkcję przekazywaną do run_blocking_workspace_io.
To opakowanie wiąże operację archiwizacji z pomocnikiem wykorzystującym wejście-wyjście procesu roboczego. Nie jest to ta sama granica implementacyjna co w przypadku rekurencyjnego usuwania: archiwizacja ma własną funkcję synchroniczną i własne operacje tarfile.
Oś awarii: rozpakowywanie
Rozpakowywanie przestrzeni roboczej ma trzecią odrębną ścieżkę. Implementacja UnixLocal wykonuje rozpakowywanie w procesie roboczym, opakowując tworzenie katalogu głównego, tarfile.open i safe_extract_tarfile w synchroniczną funkcję przekazywaną do run_blocking_workspace_io.
Niezmiennik rozpakowywania obejmuje zatem wszystkie trzy operacje w tej funkcji synchronicznej: utworzenie katalogu głównego, otwarcie archiwum i jego bezpieczne rozpakowanie. Przeniesienie tylko jednej z tych operacji nie byłoby zgodne z udokumentowaną implementacją.
Akt I: kierowanie każdej operacji przestrzeni roboczej do wejścia-wyjścia procesu roboczego
Implementacja rozdziela trzy operacje przestrzeni roboczej, zapewniając im jednocześnie takie samo rozwiązanie polegające na unikaniu pracy w pętli zdarzeń:
- rekurencyjne usuwanie katalogu jest kierowane do procesu roboczego;
- archiwizacja opakowuje
tarfile.openitar.addw funkcji synchronicznej przekazywanej dorun_blocking_workspace_io; - rozpakowywanie opakowuje tworzenie katalogu głównego,
tarfile.openisafe_extract_tarfilew funkcji synchronicznej przekazywanej dorun_blocking_workspace_io.
Są to trzy ścieżki implementacji, a nie jedna uogólniona reguła dotycząca systemu plików. Przegląd kodu lub test regresyjny powinien zachowywać każdą z tych ścieżek jawnie.
Dlaczego anulowanie tworzy odrębną granicę własności pracy przez proces roboczy
Samo wykonywanie pracy przestrzeni roboczej w procesie roboczym nie opisuje jeszcze zachowania po anulowaniu wywołującego. Anulowanie wprowadza odrębną granicę: relację między anulowaniem wywołującego a zadaniem procesu roboczego, które już wykonuje operację.
Zachowanie pomocnika jest jednoznaczne. run_blocking_workspace_io uruchamia asyncio.to_thread jako osobne zadanie, nadal czeka po otrzymaniu przez wywołującego asyncio.CancelledError i pobiera wynik zadania procesu roboczego przed ponownym zgłoszeniem anulowania.
Jest to niezmiennik własności pracy przez proces roboczy. Anulowanie jest przekazywane dalej dopiero po pobraniu wyniku zadania procesu roboczego. Należy go analizować osobno od pytania, czy operacje wejścia-wyjścia przestrzeni roboczej zostały wyprowadzone poza pętlę zdarzeń.
Oś awarii: anulowanie przed uzyskaniem wyniku procesu roboczego
Oś anulowania obejmuje dwóch uczestników: wywołującego oraz zadanie procesu roboczego utworzone dla asyncio.to_thread.
run_blocking_workspace_iouruchamiaasyncio.to_threadjako osobne zadanie.- Wywołujący otrzymuje
asyncio.CancelledError, gdy zadanie procesu roboczego nadal istnieje. - Pomocnik nadal czeka, zamiast natychmiast kończyć obsługę anulowania.
- Wynik zadania procesu roboczego zostaje pobrany.
- Anulowanie zostaje zgłoszone ponownie.
Najważniejsza granica przebiega między krokami trzecim i czwartym. Pomocnik nie zgłasza ponownie anulowania przed pobraniem wyniku zadania procesu roboczego.
Niezmiennik bezpieczny pod względem anulowania: czekaj przed ponownym zgłoszeniem
Reguła bezpieczeństwa anulowania różni się zatem od unikania pracy w pętli zdarzeń: po otrzymaniu anulowania run_blocking_workspace_io nadal czeka na zadanie procesu roboczego i pobiera jego wynik, a dopiero potem ponownie zgłasza asyncio.CancelledError.
Reguła ta nie zastępuje trzech reguł kierowania pracy z Aktu I. Określa własność zadania procesu roboczego po dostarczeniu anulowania do wywołującego.
Kształt testu regresyjnego: obserwowanie zakończenia rozpakowywania podczas anulowania
Wykonywany osobno test regresyjny anulowania zapisuje rozpoczęcie i zakończenie rozpakowywania wokół anulowania, sprawdza asyncio.CancelledError i potwierdza, że strumień archiwum pozostaje otwarty.
Taki kształt testu sprawdza granicę anulowania bezpośrednio. Obserwuje przedział czasu rozpakowywania, weryfikuje anulowanie widoczne dla wywołującego i sprawdza stan strumienia archiwum. Różni się od testu, który sprawdza wyłącznie, czy usuwanie, archiwizacja lub rozpakowywanie korzysta ze ścieżki procesu roboczego.
Zweryfikowany wynik testu regresyjnego
W komicie 494ea5978778a4daa48b513419dc5786084802d4 test regresyjny anulowania wybrał jeden test hydrate_workspace_cancellation i zakończył się powodzeniem; pominięto 14 testów.
Jest to ograniczony wynik testu dla tego komitu i tego wyboru. Nie jest to produkcyjny test wydajności ani ogólne twierdzenie dotyczące innych środowisk uruchomieniowych lub repozytoriów.
Lista kontrolna operacji
Przeglądaj obie granice poprawności osobno:
- **Unikanie pracy w pętli zdarzeń:** rekurencyjne usuwanie jest kierowane do procesu roboczego; archiwizacja opakowuje
tarfile.openitar.addw funkcji procesu roboczego; rozpakowywanie opakowuje tworzenie katalogu głównego,tarfile.openisafe_extract_tarfilew funkcji procesu roboczego. - **Własność bezpieczna pod względem anulowania:**
run_blocking_workspace_ionadal czeka poasyncio.CancelledError, pobiera wynik zadania procesu roboczego i dopiero potem ponownie zgłasza anulowanie. - **Dowody regresji:** test anulowania obserwuje rozpoczęcie i zakończenie rozpakowywania, sprawdza
asyncio.CancelledError, potwierdza, że strumień archiwum pozostaje otwarty, oraz ma odnotowane pomyślne wykonanie dla wskazanego komitu.
Traktowanie tych elementów jako osobnych kontroli zapobiega pomyleniu niezmiennika kierowania pracy do procesu roboczego z niezmiennikiem własności podczas anulowania.
Komentarze (0)
Brak komentarzy.
Dodaj komentarz
Komentarze są publikowane po moderacji. Adres e-mail nie będzie widoczny publicznie.