Obsługa wyjątków w programie, który musi działać 24/7

14

Czytałem, że powinniśmy wychwytywać tylko wyjątki, które można obsłużyć, co sprawia, że ​​łapanie podstawowej klasy wyjątków (w tym przypadku C #) jest złym pomysłem (oprócz innych powodów). Obecnie jestem częścią projektu, w którym do tej pory nie widziałem niczego poza wychwyceniem podstawowego wyjątku. Wspomniałem, że uważa się to za złą praktykę, ale odpowiedź brzmiała: „Ta usługa musi działać 24 godziny na dobę, 7 dni w tygodniu, więc tak właśnie jest”.

Ponieważ nie otrzymałem dobrej odpowiedzi na to, jak poprawnie obsługiwać wyjątki w programie, który musi działać 24/7, jestem teraz tutaj. Nie udało mi się znaleźć żadnych informacji / sugestii dotyczących postępowania z wyjątkami w „krytycznych” programach / usługach, które muszą działać przez całą dobę (w tym przypadku uważam, że może być w porządku, jeśli usługa nie działa przez minutę lub dwa, więc nawet nie krytyczne). Rozumiem, że zależy to od dokładnej natury programu. Wymagania dotyczące programu, który może powodować problemy zagrażające życiu, są zupełnie inne w porównaniu do skanera dziennika dla gry online.

Dwa przykłady:

1: Usługa typu wyprzedzająca dla klientów kolei brytyjskiej, używana podczas wyszukiwania stacji kolejowych w Internecie.

2: Program, który automatycznie kontroluje przełączniki kolejowe dla powyższych kolei w oparciu o informacje w czasie rzeczywistym dostarczane z różnych czujników na torach, pociągach itp.

Pierwszy program prawdopodobnie nie spowodowałby poważnego problemu, gdyby upadł na minutę lub dwie, podczas gdy ten drugi mógłby spowodować ofiary wśród ludzi. Sugestie, jak sobie z tym poradzić? Wskaźnik do miejsca, w którym mogę znaleźć więcej informacji i przemyślenia na ten temat?

użytkownik1323245
źródło
2
Odwijanie stosów podczas obsługi wyjątków w aplikacji w czasie rzeczywistym (sic!) Może zniszczyć pociąg.
Deer Hunter
4
@DeerHunter Nieprawidłowe kodowanie bez wyjątków, może mieć ten sam wynik.
BЈовић
9
Okej, więc ty catch Exception. To nie znaczy, że Twój program działa , oznacza to, że awarie powodują, że stan aplikacji ulega uszkodzeniu podczas działania, co jest znacznie bardziej niebezpiecznym miejscem. Awaria programu może być katastrofalna, ale program, który jest w nieprawidłowym stanie, ale nadal wykonuje działania, może być katastrofalnie aktywny .
Phoshi
1
Jeśli aplikacja musi działać 24/7, jest gdzieś nieskończona pętla i ta nieskończona pętla powinna być lepiej owinięta wokół konstrukcji, która wychwytuje wszystkie nieobsługiwane wyjątki. Jeśli tak nie jest, nieobsługiwany wyjątek przeniknie do już istniejącego modułu obsługi catch-all, który znajduje się poza głównym i kaboom! aplikacja 24/7 wygasa.
David Hammen

Odpowiedzi:

7

Niektóre funkcje językowe, takie jak

  • Zbieranie śmieci
  • Systemy wyjątkowe
  • Leniwa ocena

nie są ogólnie przydatne w systemie czasu rzeczywistego. Prawdopodobnie należy wybrać język bez tych funkcji i spróbować udowodnić pewne właściwości, takie jak maksymalne wykorzystanie pamięci lub maksymalny czas reakcji.


Gdy program musi działać w sposób ciągły, ale dopuszczalne są krótkie i nieglobalne niepowodzenia, możemy zastosować strategię podobną do Erlanga. Erlang jest współbieżnym, funkcjonalnym językiem programowania. Zwykle program napisany w Erlangu będzie się składał z wielu procesów roboczych, które mogą się ze sobą komunikować (model aktora). Jeśli jeden wątek roboczy napotka wyjątek, zostanie on ponownie uruchomiony. Chociaż oznacza to krótkie przestoje, inni aktorzy mogą kontynuować jak zwykle.

Podsumowując: W solidnym programie różne części są izolowane od siebie i mogą być ponownie uruchomione lub skalowane niezależnie.

Zasadniczo potrzebujemy fragmentu kodu równoważnego z tym:

while (true) {
  try {
    DoWork();
  }
  catch (Exception e) {
    log(e);
  }
}

plus sposób na zakończenie pętli. Taka pętla napędzałaby następnie każdy wątek roboczy.


Problem z ignorowaniem błędów przez catch-all polega na tym, że niezmienniki twojego programu mogły zostać naruszone przez przyczynę błędu i że kolejne operacje mogą być bezużyteczne. Dobrym rozwiązaniem jest udostępnianie danych niezależnym pracownikom. Ponowne uruchomienie pracownika odbuduje wszystkie niezbędne niezmienniki. Oznacza to, że muszą komunikować się inaczej, np. Poprzez wysyłanie wiadomości. Stan aktora nie może być częścią niezmienników innych aktorów.

Innym problemem związanym z przechwytywaniem zbyt wielu wyjątków jest to, że nie wszystkie wyjątki można naprawić przez ponowne uruchomienie, nawet przy zachowaniu takich środków ostrożności. W przeciwnym razie trudne problemy, takie jak brak pamięci, można rozwiązać przez ponowne uruchomienie. Ale ponowne uruchomienie nie pomoże ci odzyskać łączności z Internetem po wyciągnięciu fizycznego kabla.

amon
źródło
1
Tak, ale sytuacja wygląda tak, jakby „fizyczny kabel został wyciągnięty” jest dokładnie wtedy, gdy chcesz, aby dziennik wyjątków zapełnił się, dopóki ktoś nie włoży kabla z powrotem, a następnie wszystko zacznie działać ponownie bez dalszego ręcznego restartowania aplikacji.
Mark Hurd
2

Aby odpowiedzieć na twoje pytanie, musisz zrozumieć, jakie są wyjątki i jak one działają.

Wyjątki są zwykle zgłaszane w przypadku wystąpienia takich błędów, gdy wymagana jest pomoc użytkownika. W takich przypadkach nie ma znaczenia, ile czasu zajmuje odwrócenie stosu i obsłużenie wyjątku.

Bez programów obsługi przechwytywania program zatrzymuje wykonywanie. W zależności od konfiguracji i wymagań może być do zaakceptowania.

W twoich szczególnych przypadkach:

  1. jeśli zapytanie nie może zostać wykonane (na przykład zła nazwa miasta), poinformuj użytkownika o błędzie i poproś o jego naprawienie.
  2. jeśli nie otrzymujesz informacji z czujnika krytycznego, nie ma sensu kontynuować bez poproszenia operatora o naprawienie problemu.

Oznacza to, że w obu przypadkach może być sensowne zastosowanie wyjątków, z większą ostrożnością w programie RT, aby wskazać tylko poważne problemy, w przypadku których nie można kontynuować wykonywania.

BЈовић
źródło
1

Do tej pory nie widziałem niczego poza wyjątkiem wyjątku podstawowego.

Wygląda na to, że jest tu problem, ponieważ wyjątki nie są odpowiednio traktowane. Złapanie wyjątków w odpowiednim momencie i podjęcie odpowiednich działań (w zależności od rodzaju wyjątku) sprawi, że usługa będzie działała w znacznie bardziej niezawodny sposób.

Jeśli usługa musi być kontynuowana, prawdopodobnie ważne jest, aby działała zgodnie z przeznaczeniem. Biorąc pod uwagę twój przykład, jeśli program sterujący rozjazdami kolejowymi zgłasza wyjątek, może to wskazywać na problem z komunikacją z czujnikami związanymi z bezpieczeństwem. Jeśli złapiesz wyjątek podstawowy i będziesz kontynuować, usługa może działać, ale może nie działać zgodnie z przeznaczeniem, prowadząc do katastrofy.

Alternatywnie, jeśli złapiesz wyjątek zgłoszony, gdy wystąpi awaria komunikacji z czujnikiem i odpowiednio sobie z nim poradzisz (tj. Zatrzymasz pociągi w dotkniętym obszarze), twoja usługa jest uruchomiona i nikogo nie zabiłeś.

Tak więc, jak rozumiem pytanie, sugerowałbym, że w pierwszej kolejności lepiej byłoby dodać bardziej szczegółową obsługę wyjątków, niż usuwać podstawowe typy wyjątków.

Matt
źródło
0

W odniesieniu do punktu 2: nie używaj C #. Nie jest to język w czasie rzeczywistym, a ty będziesz się krzywda, jeśli starają się używać go jako taki.

Dla punktu 1: możesz przejść w erlang: pozwól mu się zawiesić, a następnie uruchom ponownie

miniBill
źródło
Moje wykorzystanie C # i wiedza nie są w pobliżu punktu 2 (przełączanie ścieżek w czasie rzeczywistym). Jestem ciekawy, dlaczego C # jest tak nieodpowiedni do takiego zadania?
Michael O'Neill
1
Głównie: śmieciarz powoduje, że zachowanie programu w odniesieniu do czasu jest nieprzewidywalne. Ponadto środowisko wykonawcze jest zbyt złożone, aw tych kontekstach potrzebne są proste rzeczy, są bardziej przewidywalne
miniBill
0

Deklaracja: to tylko myśli, nie mam doświadczenia.

Sądzę, że program spełniający wymagania drugiego przykładu powinien być wyjątkowo modułowy . W związku z tym moduły będą mogły zostać zrestartowane bez destabilizacji systemu.

Na przykład obiekt, który nie potwierdzi twierdzenia o stanie wewnętrznym, powinien móc zostać zniszczony i ponownie utworzony, powiadamiając w tym procesie wszystkich swoich konsumentów i dostawców. Mówiąc dokładniej, jeśli program kontroluje przełączniki linii kolejowej i nie powiedzie się twierdzenie w pętli decyzyjnej, nadal może uruchomić moduł awaryjny, który zatrzymuje wszystkie zaangażowane pociągi i czeka na ponowne zainicjowanie głównego modułu decyzyjnego.

Bardziej realistycznie wprowadzono by redundancję - powielanie sprzętu i oprogramowania. Jedna instancja jest podłączona do kontrolowanego systemu, a druga jest wolna. W przypadku wykrycia błędu systemy są przełączane.

Przykładem są dwa procesy na tym samym komputerze, które monitorują się nawzajem, a jeśli jeden zostanie zabity, drugi odradza go i oddziela swój macierzysty PID od siebie.

Vorac
źródło