Domanda

Abbiamo un Servizio di Windows scritto in C#.Il servizio genera un thread che fa questo:

private void ThreadWorkerFunction()
{
  while(false == _stop) // stop flag set by other thread
  {
    try
    {
      openConnection();

      doStuff();

      closeConnection();
    }
    catch (Exception ex)
    {
      log.Error("Something went wrong.", ex);

      Thread.Sleep(TimeSpan.FromMinutes(10));
    }
  }
}

Abbiamo messo il Thread.Dormire dopo un paio di volte quando il database era andato via e siamo tornati a 3Gb di file di log pieno di errori di connessione al database.

Questo ha funzionato bene per mesi, ma di recente abbiamo visto un paio di casi in cui il registro.Errore() dichiarazione di registri di Sistema".InvalidOperationException:Questo SqlTransaction ha completato;non è più utilizzabile" eccezione e quindi non viene mai indietro.Il servizio può essere lasciato in esecuzione per giorni, ma niente di più verrà registrato.

Dopo aver fatto qualche lettura so che il Thread.Il sonno non è l'ideale, ma perché semplicemente non tornare mai più?

È stato utile?

Soluzione

Scavare e scoprire?Stick un debugger su quel bastardo!

Posso vedere almeno le seguenti possibilità:

  1. il sistema di registrazione si blocca;
  2. il thread è uscito bene, ma il servizio è ancora in esecuzione qualche altra parte è un errore di logica.

E forse, ma quasi certamente non lo è, la seguente:

  • Sleep() si blocca.

Ma in ogni caso, il collegamento di un debugger ti mostrerà se il thread è ancora lì e se davvero si è bloccato.

Altri suggerimenti

Abbiamo messo il Thread.Dormire dopo un paio di volte quando il database era andato via e siamo tornati a 3Gb di file di log pieno di errori di connessione al database.

Io penso che un'opzione migliore sarebbe di fare in modo che il vostro sistema di registrazione intrappolati duplicati, in modo che possa scrivere qualcosa di simile, "Il precedente messaggio è stato ripetuto N volte".

Si supponga ho scritto una nota su come si dovrebbe aprire la connessione all'ultimo momento possibile e chiudere il prima possibile, piuttosto che abbracciano un potenziale enorme funzione nel modo che ti ho fatto (ma forse è un manufatto di vostra dimostrativo codice e l'applicazione è in realtà scritto correttamente).

Quando si dice che la segnalazione dell'errore da te descritto, vuoi dire che questo gestore è la segnalazione dell'errore?Il motivo non è chiaro per me è che nel frammento di codice è dire "Qualcosa è andato storto", ma non dire che nella tua descrizione;Non vorrei che questo sia qualcosa di così stupido come l'eccezione viene catturato da qualche altra parte, e il codice è di rimanere bloccati da qualche altra parte che il sonno.

Ho avuto esattamente lo stesso problema.Spostando il Sonno di linea al di fuori del gestore di eccezioni risolto il problema per me, come questo:

bool hadError = false;
try {
  ...
} catch (...) {
  hadError = true;
}
if (hadError)
  Thread.Sleep(...);

Interrompere il thread non sembra funzionare nel contesto di un gestore di eccezioni.

Avete provato a usare Monitor.Pulse (assicurarsi che il thread sta utilizzando la gestione dei thread prima di eseguire questo) per ottenere il thread per fare qualcosa?Se funziona, allora si sta andando ad avere per guardare un po ' di più il tuo filettatura logica.

Dal codice che hai postato, non è chiaro che dopo viene generata un'eccezione il sistema è sicuramente in grado di riavviare - ad es.se l'eccezione viene da doStuff(), quindi il flusso di controllo passa indietro (dopo 10 minuti di attesa) per openConnection(), senza mai passare attraverso closeConnection().

Ma come altri hanno detto, basta collegare un debugger e trovare dove è realmente.

Provare A Filo.Sonno(10 * 60 * 1000)

Non ho mai pienamente capito cosa stava succedendo, ma sembrava essere correlato a ThreadInterruptedExceptions essere gettato durante i 10 minuti di sonno, così ho modificato il codice per:

private void ThreadWorkerFunction()
{
  DateTime? timeout = null;

  while (!_stop)
  {
    try
    {
      if (timeout == null || timeout < DateTime.Now)
      {
        openDatabaseConnections();

        doStuff();

        closeDatabaseConnections();
      }
      else
      {
        Thread.Sleep(1000);
      }
    }
    catch (ThreadInterruptedException tiex)
    {
      log.Error("The worker thread was interrupted... ignoring.", tiex);
    }
    catch (Exception ex)
    {
      log.Error("Something went wrong.", ex);

      timeout = DateTime.Now + TimeSpan.FromMinutes(10);
    }
  }
}

A parte in particolare cattura la ThreadInterruptedException, questo solo si sente più sicuro in quanto tutto il sonno avviene all'interno di un blocco try, quindi, qualcosa di inaspettato che succede verrà registrato.Cercherò di aggiornare questa risposta, se mai riuscirò a saperne di più.

Sono imbattuto in questo durante la ricerca di un Filo.Problema di sonno di mio.Questo può o non può essere correlato, ma se il tuo doSomething() genera un'eccezione, closeDatabaseConnections() non succederà mai, che ha un certo potenziale per perdite di risorse..Mi piacerebbe mettere che in un blocco finally.Solo qualcosa a cui pensare.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top