Gdy asynchroniczny strumień się kończy, a run loop zawiódł: zachowanie wyjątku na granicy
Objaw awarii: stream_events kończy się bez ujawnienia wyjątku run loopa
Zakończenie asynchronicznego strumienia zdarzeń nie jest samo w sobie dowodem, że bazowa praca się powiodła. W opisanym tu przypadku awarii metoda odpowiedzi modelu rzuca RuntimeError zanim zaczyna zwracać zdarzenia strumienia. W zweryfikowanej rewizji konsumpcja stream_events rzuca RuntimeError z komunikatem run loop boom.
Ta awaria musi pozostać widoczna dla wywołującego. W przeciwnym razie kod czekający na granicę strumienia może pomylić zakończenie z udaną pracą i rozpocząć akcję zależną bez wcześniejszego sprawdzenia wyniku run loopa.
Granica wyjątków: definicja run_loop_exception i stany zwracające None
Patch dodaje właściwość run_loop_exception. Gdy zadanie run loopa w tle się zakończyło i nie zostało anulowane, właściwość zwraca wyjątek rzucony przez to zadanie.
Właściwość zwraca None w trzech stanach: gdy run loop zakończył się bez błędu, gdy jeszcze się nie zakończył oraz gdy został anulowany. Stany te odróżniają zaobserwowaną awarię run loopa od zadania niedokończonego lub anulowanego i od czystego zakończenia.
Granica jest więc jawnie zdefiniowana: wywołujący może inspectować osiadły wyjątek run loopa zamiast traktować zakończenie strumienia jako kompletny wynik operacji.
Wyścig: ponowne sprawdzenie po osiadnięciu run loopa
W zweryfikowanej rewizji patch sprawdza ponownie błędy także po pełnym osiadnięciu run loopa. Obsługuje to zaobserwowany przypadek, w którym wyjątek „wyprzedza" sentinel strumienia: granica strumienia może zostać osiągnięta, zanim finalny stan wyjątku zadania w tle będzie dostępny, ale ścieżka zapisanego wyjątku może ujawnić awarię po zakończeniu osiadania.
To zachowuje relację przyczynową między zadaniem run loopa a konsumentem strumienia. Konsument nie musi wnioskować o sukcesie z sentinela; może zaobserwować wyjątek zarejestrowany przez osiadłe zadanie.
Oś awarii: model regresji rzuca RuntimeError przed zwróceniem zdarzeń
Przypadek regresji używa modelu, którego metody odpowiedzi rzucają RuntimeError przed zwróceniem zdarzeń strumienia. Oś awarii wygląda tak:
- Run loop wywołuje właściwą metodę odpowiedzi modelu.
- Metoda odpowiedzi rzuca
RuntimeErrorz komunikatemrun loop boomprzed wyprodukowaniem zdarzeń strumienia. - Zadanie run loopa osiada z tym wyjątkiem.
- Konsument strumienia obserwuje awarię, gdy konsumuje
stream_events. - Po konsumpcji nieudanego strumienia
result.run_loop_exceptionjest nie-nullowy i zawiera ten samRuntimeError.
Zapisany wyjątek nie zastępuje awarii strumienia. Jest to jawna granica inspekcji, która pozostaje dostępna po osiadnięciu zadania w tle.
Kształt regresji: asercje awarii strumienia i zapisanego run_loop_exception
Regresja musi pokrywać obie obserwowalne strony granicy. Po pierwsze, konsumpcja stream_events w przypadku awarii musi rzucać RuntimeError z komunikatem run loop boom. Po drugie, po konsumpcji nieudanego strumienia result.run_loop_exception musi być nie-nullowy i zawierać ten sam RuntimeError.
Trzymanie tych asercji razem chroni łańcuch przyczynowy: strumień raportuje awarię, a wynik zachowuje osiadły wyjątek do inspekcji. Test sprawdzający wyłącznie konsumpcję strumienia nie zweryfikowałby granicy zapisanego wyjątku; test sprawdzający wyłącznie właściwość nie zweryfikowałby awarii widocznej dla konsumenta.
Oś sukcesu: czysty strumień zostawia run_loop_exception jako None
Przypadek sukcesu asertuje, że run_loop_exception jest None po zakończeniu stream_events bez błędu. To komplementarny niezmiennik przypadku awarii: czysto zakończony strumień nie wypełnia zapisanego wyjątku.
Razem przypadki awarii i sukcesu odróżniają zakończenie z wyjątkiem od czystego zakończenia. Zachowują też udokumentowane zachowanie None dla run loopa, który zakończył się bez błędu.
Weryfikacja: 11-testowa suitka cancel-streaming na CPython 3.13.13
W zweryfikowanej rewizji upstreamu suitka tests/test_cancel_streaming.py zebrała 11 testów i wszystkie 11 przeszło na CPython 3.13.13.
To ograniczona weryfikacja suitki testów cancel-streaming w tej rewizji. Nie ustala zachowania poza zweryfikowaną rewizją ani nie formułuje uniwersalnej tezy o protokołach strumieniowania asynchronicznego.
Wniosek operacyjny: zinspectuj osiadły wyjątek przed startem pracy zależnej
Dla tego API traktuj zakończenie asynchronicznego strumienia zdarzeń jako niewystarczający dowód udanej pracy. Wyjątek run loopa musi pozostać obserwowalny po zakończeniu strumienia, a wywołujący powinni zachować jawną granicę inspekcji wyjątku przed uruchomieniem pracy zależnej.
Kształt focused regression jest równie ważny: użyj metody odpowiedzi rzucającej RuntimeError przed zwróceniem zdarzeń, asertuj awarię zaobserwowaną przy konsumpcji stream_events, asertuj że run_loop_exception zachowuje ten sam wyjątek, i osobno asertuj, że czysty strumień zostawia właściwość jako None.
Komentarze (0)
Brak komentarzy.
Dodaj komentarz
Komentarze są publikowane po moderacji. Adres e-mail nie będzie widoczny publicznie.