Gestione delle eccezioni in un programma che deve essere eseguito 24/7


14

Ho letto che dovremmo catturare solo le eccezioni che possono essere gestite, il che rende cattiva la classe delle eccezioni di base (C # in questo caso) una cattiva idea (oltre ad altri motivi). Attualmente faccio parte di un progetto in cui finora non ho ancora visto altro che l'eccezione di base catturata. Ho detto che è considerato una cattiva pratica farlo, ma la risposta è stata "Questo servizio deve essere eseguito 24/7, quindi è così".

Dal momento che non ho avuto una buona risposta su come gestire correttamente le eccezioni in un programma che deve essere eseguito 24/7, ora sono qui. Non sono riuscito a trovare informazioni / suggerimenti su come gestire la gestione delle eccezioni in programmi / servizi "critici" che devono essere eseguiti 24 ore su 24 (e in questo caso credo che potrebbe andare bene se il servizio è inattivo per un minuto o due, quindi nemmeno critici). Capisco che dipende dalla natura esatta del programma. I requisiti per un programma che può causare problemi potenzialmente letali sono abbastanza diversi rispetto a uno scanner di log per un gioco online.

Due esempi:

1: un servizio di anticipazione per i clienti delle ferrovie della Bretagna, utilizzato durante la ricerca online di stazioni ferroviarie.

2: Un programma che controlla automaticamente gli interruttori ferroviari per le ferrovie di cui sopra sulla base delle informazioni in tempo reale fornite da vari sensori nei binari, treni, ecc.

Il primo programma probabilmente non causerebbe un grosso problema se si interrompesse per un minuto o due, dove quest'ultimo potrebbe causare vittime umane. Suggerimenti su come gestirli? Puntatore a dove posso trovare maggiori informazioni e riflessioni su questo problema?


2
Impilare lo svolgimento durante la gestione delle eccezioni in un'app in tempo reale (sic!) Può distruggere un treno.
Deer Hunter,

4
@DeerHunter Una codifica errata senza eccezioni, può avere lo stesso risultato.
BЈовић,

9
Va bene, anche tu catch Exception. Ciò non significa che il programma funziona , significa che i guasti lasciare lo stato dell'applicazione ottenere danneggiato mentre continua ad eseguire, un luogo molto più pericoloso di essere. Un programma bloccato potrebbe essere disastroso, ma un programma che si trova in uno stato non valido ma che sta ancora eseguendo azioni può essere attivamente disastroso.
Phoshi,

1
Se l'applicazione deve funzionare 24 ore su 24, 7 giorni su 7, c'è un ciclo infinito da qualche parte e questo ciclo infinito dovrebbe essere avvolto attorno a un costrutto che cattura tutte le eccezioni non gestite. In caso contrario, un'eccezione non gestita verrà percolata dal gestore catch-all già esistente che è al di fuori di main e kaboom! l'applicazione 24/7 termina.
David Hammen,

Risposte:


7

Alcune funzionalità linguistiche come

  • Raccolta dei rifiuti
  • Sistemi di eccezione
  • Valutazione pigra

non sono generalmente utili in un sistema in tempo reale. Probabilmente si dovrebbe scegliere una lingua senza queste funzionalità e provare a dimostrare determinate proprietà come il massimo utilizzo della memoria o il massimo tempo di risposta.


Quando un programma deve essere eseguito continuamente, ma sono accettabili guasti brevi e non globali, allora potremmo usare una strategia simile a Erlang. Erlang è un linguaggio di programmazione concorrente e funzionale. Di solito, un programma scritto in Erlang consisterà in più processi di lavoro che possono comunicare tra loro (modello dell'attore). Se un thread di lavoro rileva un'eccezione, viene riavviato. Mentre ciò implica un breve tempo di inattività, gli altri attori possono continuare come al solito.

Riassumendo: in un programma solido, varie parti sono isolate l'una dall'altra e possono essere riavviate o ridimensionate in modo indipendente.

Quindi in sostanza abbiamo bisogno di un pezzo di codice equivalente a questo:

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

oltre a un modo per terminare il loop. Un ciclo del genere dovrebbe quindi guidare ogni thread di lavoro.


Un problema con l'ignorare gli errori tramite un catch-all è che gli invarianti del tuo programma potrebbero essere stati violati dalla causa dell'errore e che le successive operazioni potrebbero essere inutili. Una buona soluzione a ciò è quella di non condividere dati tra lavoratori indipendenti. Il riavvio di un lavoratore ricostruirà tutti gli invarianti necessari. Ciò significa che devono comunicare in modo diverso, ad esempio tramite l'invio di messaggi. Lo stato di un attore non può far parte degli invarianti di altri attori.

Un altro problema nel rilevare troppe eccezioni è che non tutte le eccezioni sono riparabili riavviando, anche quando si prendono tali precauzioni. In caso contrario, riavviare è possibile gestire problemi difficili come l'esaurimento della memoria . Ma un riavvio non ti aiuterà a riguadagnare la connettività Internet quando è stato estratto un cavo fisico.


1
Sì, ma la situazione come "un cavo fisico è stato estratto" è esattamente quando vuoi solo riempire il registro delle eccezioni fino a quando qualcuno non ricollega il cavo, quindi le cose ricominciano a funzionare, senza ulteriore riavvio manuale dell'applicazione.
Mark Hurd,

2

Per rispondere alla tua domanda, bisogna capire quali sono le eccezioni e come funzionano.

In genere vengono generate eccezioni quando si verificano tali errori, dove è richiesta l'assistenza dell'utente. In questi casi, non importa quanto tempo ci vuole per sciogliere lo stack e gestire l'eccezione.

Senza i gestori di cattura, il programma interrompe l'esecuzione. A seconda della configurazione e dei requisiti, potrebbe essere accettabile.

Nei tuoi casi specifici:

  1. se la query non può essere eseguita (ad esempio, nome di città errato), informare l'utente dell'errore e chiedere di risolverlo.
  2. se non si ottengono informazioni da un sensore critico, non ha molto senso continuare senza chiedere all'operatore di risolvere il problema.

Ciò significa che in entrambi i casi può essere logico utilizzare le eccezioni, con maggiore attenzione in un programma RT per indicare solo problemi gravi in ​​cui non è possibile continuare l'esecuzione.


1

Finora non ho ancora visto altro che l'eccezione di base catturata.

Sembra che ci sia un problema qui, in quanto le eccezioni non vengono trattate in modo appropriato. Catturare le eccezioni nel punto appropriato e intraprendere le azioni appropriate (a seconda del tipo di eccezione) manterrà il servizio in esecuzione in modo molto più affidabile.

Se il servizio deve continuare, presumibilmente è importante che funzioni come previsto. Dato il tuo esempio, se un programma che controlla gli interruttori ferroviari genera un'eccezione, potrebbe indicare che c'è un problema di comunicazione con i sensori relativi alla sicurezza. Se si rileva l'eccezione di base e si continua, il servizio potrebbe essere eseguito, ma potrebbe non funzionare come previsto e provocare un disastro.

In alternativa, se si rileva l'eccezione generata in caso di interruzione della comunicazione con il sensore e la si gestisce in modo appropriato (ad esempio, fermare i treni nell'area interessata), il servizio è attivo e non si è ucciso nessuno.

Quindi, quando capisco la domanda, suggerirei che in prima istanza sarebbe meglio cercare di aggiungere una gestione delle eccezioni più specifica piuttosto che rimuovere i gestori del tipo di eccezione di base.


0

Per quanto riguarda il punto 2: non usare C #. Non è un linguaggio in tempo reale e ti farà male se provi a usarlo come tale.

Per il punto 1: potresti andare nel modo sbagliato: lascialo andare in crash, quindi riavvia


L'utilizzo e la competenza di C # non riguardano il punto 2 (cambio traccia in tempo reale). Sono curioso di sapere perché C # è così inadatto per tale compito?
Michael O'Neill,

1
Soprattutto: il garbage collector rende imprevedibile il comportamento del programma, per quanto riguarda il tempo. Inoltre, l'autonomia è troppo complessa e in quei contesti hai bisogno di cose semplici, sono più prevedibili
miniBill

0

Declaimer: questi sono solo pensieri, non ho l'esperienza.

Immagino che un programma che soddisfi i requisiti del secondo esempio dovrebbe essere estremamente modulare . Di conseguenza, i moduli potranno essere riavviati, senza destabilizzare il sistema.

Ad esempio, un oggetto, in mancanza di un'asserzione per lo stato interno, dovrebbe essere in grado di essere distrutto e ricreato, notificando nel processo tutti i suoi consumatori e fornitori. Più concretamente, se il programma controlla gli interruttori della ferrovia e fallisce un'asserzione nel circuito decisionale, può comunque eseguire un modulo di emergenza, che arresta tutti i treni coinvolti e attende la reinizializzazione del modulo decisionale principale.

Più realisticamente, si introdurrebbe la ridondanza : duplicazione dell'hardware e del software. Un'istanza è cablata al sistema controllato e l'altra è in esecuzione libera. Se viene rilevato un errore, i sistemi vengono commutati.

Un esempio sono due processi sulla stessa macchina, che si controllano a vicenda e se uno viene ucciso, l'altro lo ricompone e dissocia il PID padre da se stesso.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.