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

13

Ho letto che dovremmo prendere solo eccezioni che possono essere gestite, il che rende cattiva l'idea della classe di base di base (C # in questo caso) (per 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 ore su 24, 7 giorni su 7, quindi è così."

Poiché non ho avuto una buona risposta su come gestire correttamente le eccezioni in un programma che deve essere eseguito 24 ore su 24, ora sono qui. Non sono riuscito a trovare alcuna informazione / suggerimento 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 essere ok 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 di vita sono abbastanza diversi rispetto a uno scanner di registro per un gioco online.

Due esempi:

1: un servizio type-ahead per i clienti delle ferrovie brittish, utilizzato quando cercano online le stazioni ferroviarie.

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

Il primo programma probabilmente non causerebbe un grosso problema se fosse andato giù per un minuto o due, mentre il secondo potrebbe causare vittime umane. Suggerimenti su come comportarsi con ciascuno? Puntatore a dove posso trovare più informazioni e pensieri su questo problema?

    
posta user1323245 22.01.2014 - 09:09
fonte

5 risposte

6

Alcune funzionalità linguistiche come

  • Raccolta dati obsoleti
  • Sistemi di eccezione
  • Valutazione pigra

in genere non sono utili in un sistema in tempo reale. Probabilmente dovresti scegliere una lingua senza queste funzioni e provare a provare alcune proprietà come l'utilizzo massimo della memoria o il tempo massimo di risposta.

Quando un programma ha bisogno di funzionare continuamente, ma i guasti brevi e non globali sono accettabili, allora potremmo usare una strategia tipo Erlang. Erlang è un linguaggio di programmazione concomitante e funzionale. Di solito, un programma scritto in Erlang consisterà in più processi di lavoro che possono comunicare tra loro (modello attore). Se un thread di lavoro incontra un'eccezione, viene riavviato. Sebbene ciò implichi un breve periodo di inattività, gli altri attori possono continuare come al solito.

Per riassumere ciò: in un programma robusto, varie parti sono isolate l'una dall'altra e possono essere riavviate o ridimensionate in modo indipendente.

Quindi fondamentalmente abbiamo bisogno di un pezzo di codice equivalente a questo:

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

più un modo per terminare il ciclo. Un tale ciclo quindi guiderà 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 operazioni successive potrebbero essere inutili. Una buona soluzione a questo è di non condividere dati tra lavoratori indipendenti. Riavviare un lavoratore ricostruirà tutti gli invarianti necessari. Ciò significa che devono comunicare in modo diverso, ad es. attraverso il messaggio invia. Lo stato di un attore non può far parte degli invarianti di altri attori.

Un altro problema con la cattura di troppe eccezioni è che non tutte le eccezioni sono riparabili riavviando, anche quando si adottano tali precauzioni. Altrimenti, problemi rigidi come l'esaurimento della memoria possono essere gestiti riavviando. Ma un riavvio non ti aiuterà a riconquistare la connettività internet quando un cavo fisico è stato estratto.

    
risposta data 22.01.2014 - 09:43
fonte
2

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

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

Senza gestori di catch, 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), informa l'utente dell'errore e chiedi di correggerlo.
  2. se non ricevi le 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 opportuno utilizzare eccezioni, con più attenzione in un programma RT per indicare solo problemi gravi in cui non è possibile continuare l'esecuzione.

    
risposta data 22.01.2014 - 11:27
fonte
1

I so far have yet to see anything but the base exception being caught.

Sembra che ci sia un problema qui, in quanto le eccezioni non vengono gestite 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 switch ferroviari genera un'eccezione potrebbe indicare che c'è un problema nel comunicare con i sensori relativi alla sicurezza. Se rilevi l'eccezione di base e continui, il servizio può essere eseguito, ma potrebbe non funzionare come previsto e portare a un disastro.

In alternativa, se rilevi l'eccezione lanciata quando c'è un errore di comunicazione con il sensore e gestisci in modo appropriato (cioè ferma i treni nell'area interessata) il tuo servizio è attivo e non hai ucciso nessuno.

Quindi, come comprendo la domanda, suggerirei che nel primo caso sarebbe meglio aggiungere una gestione delle eccezioni più specifica piuttosto che rimuovere i gestori di tipi di eccezioni di base.

    
risposta data 27.01.2014 - 21:31
fonte
0

Riguardo al punto 2: non usare C #. Non è un linguaggio in tempo reale e ti farà male se proverai a usarlo come tale.

Per il punto 1: potresti andare in modo erlang: lasciarlo in crash, quindi riavviare

    
risposta data 22.01.2014 - 09:30
fonte
0

Declaimer: questi sono solo pensieri, non ho esperienza.

Direi che un programma che soddisfi i requisiti del secondo esempio dovrebbe essere estremamente modulare . Di conseguenza, i moduli saranno in grado di 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 sta controllando gli switch della ferrovia e fallisce un assert nel ciclo decisionale, può ancora eseguire un modulo di emergenza, che arresta tutti i treni coinvolti, e attende che il principale modulo di decisione venga reinizializzato.

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

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

    
risposta data 22.01.2014 - 09:53
fonte

Leggi altre domande sui tag