Gdy strumień asynchroniczny się kończy, ale pętla wykonawcza zakończyła się błędem

Opublikowano: 10 września 2026

Zakończenie asynchronicznego strumienia zdarzeń nie oznacza jeszcze, że praca wykonywana w tle zakończyła się powodzeniem. To istotne zwłaszcza wtedy, gdy kod korzystający ze strumienia po jego zamknięciu od razu uruchamia kolejne działanie.

W opisanym przypadku metoda odpowiedzi modelu rzuca RuntimeError jeszcze przed rozpoczęciem zwracania zdarzeń. W zweryfikowanej rewizji odczyt stream_events kończy się więc RuntimeError z komunikatem run loop boom. Ten błąd musi pozostać widoczny dla kodu wywołującego — inaczej koniec strumienia można omyłkowo potraktować jako sukces całej operacji.

run_loop_exception zachowuje błąd zadania działającego w tle

Poprawka dodaje właściwość run_loop_exception. Jeżeli zadanie pętli wykonawczej działające w tle już się zakończyło i nie zostało anulowane, właściwość zwraca wyjątek rzucony przez to zadanie.

run_loop_exception zwraca None w trzech przypadkach: gdy zadanie zakończyło się poprawnie, gdy nadal trwa oraz gdy zostało anulowane.

Dzięki temu zakończenie stream_events nie musi pełnić podwójnej roli sygnału końca strumienia i wyniku całej operacji. Kod wywołujący może osobno sprawdzić, czy zakończone zadanie działające w tle pozostawiło wyjątek.

Trzeba sprawdzić błąd również po zakończeniu zadania

Samo sprawdzenie stanu w chwili dojścia do końca strumienia nie wystarcza. W zweryfikowanej rewizji błąd jest sprawdzany ponownie także po pełnym zakończeniu zadania pętli wykonawczej.

Obsługuje to zaobserwowany wyścig, w którym wyjątek pojawia się wcześniej niż sygnał końca strumienia, ale jego ostateczny stan nie jest jeszcze dostępny dokładnie w chwili osiągnięcia tej granicy. Po zakończeniu zadania zapisany wyjątek pozwala nadal poprawnie ujawnić awarię.

Przypadek regresyjny wygląda następująco:

Pętla wykonawcza wywołuje właściwą metodę odpowiedzi modelu.

Metoda rzuca RuntimeError z komunikatem run loop boom.

Zadanie pętli wykonawczej kończy się z tym wyjątkiem.

Kod odczytujący stream_events obserwuje awarię podczas konsumpcji strumienia.

Po zakończeniu nieudanego odczytu result.run_loop_exception nie jest None i zawiera ten sam RuntimeError.

Jak została sprawdzona poprawka

W zweryfikowanej rewizji upstreamu zestaw tests/test_cancel_streaming.py obejmował 11 testów. Wszystkie 11 przeszło na CPython 3.13.13.

To celowo ograniczony zakres weryfikacji dla tej konkretnej rewizji. Nie jest to ogólny dowód poprawności wszystkich możliwych protokołów asynchronicznego strumieniowania.

Co warto sprawdzać w teście regresyjnym

Dla tego API sam koniec asynchronicznego strumienia zdarzeń nie powinien być traktowany jako wystarczający dowód sukcesu. Dobry test regresyjny używa metody odpowiedzi, która rzuca RuntimeError przed zwróceniem pierwszego zdarzenia, sprawdza błąd podczas odczytu stream_events, a następnie potwierdza, że run_loop_exception zachował ten sam wyjątek.

Osobny przypadek powinien pokrywać poprawne zakończenie strumienia i sprawdzać, że run_loop_exception pozostaje wtedy None.

Komentarze (0)

Brak komentarzy.

Dodaj komentarz

Komentarze są publikowane po moderacji. Adres e-mail nie będzie widoczny publicznie.