Frage

Wir haben einen in C# geschriebenen Windows-Dienst.Der Dienst erzeugt einen Thread, der Folgendes tut:

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));
    }
  }
}

Wir haben Thread.Sleep ein paar Mal eingefügt, als die Datenbank verschwunden war und wir wieder auf 3-GB-Protokolldateien voller Datenbankverbindungsfehler zurückkamen.

Dies läuft seit Monaten einwandfrei, aber in letzter Zeit haben wir einige Fälle gesehen, in denen die log.Error()-Anweisung eine „System.InvalidOperationException“ protokolliert:Diese SqlTransaction wurde abgeschlossen;es ist nicht länger verwendbar“-Ausnahme und kommt dann nie wieder zurück.Der Dienst kann tagelang laufen bleiben, aber es wird nichts mehr protokolliert.

Nachdem ich etwas gelesen habe, weiß ich, dass Thread.Sleep nicht ideal ist, aber warum sollte es einfach nie wiederkommen?

War es hilfreich?

Lösung

Reinschnuppern und es herausfinden?Stecken Sie diesem Bastard einen Debugger auf!

Ich sehe zumindest folgende Möglichkeiten:

  1. das Protokollierungssystem hängt;
  2. Der Thread wurde problemlos beendet, aber der Dienst läuft noch, weil in einem anderen Teil ein Logikfehler vorliegt.

Und vielleicht, aber mit ziemlicher Sicherheit nicht, Folgendes:

  • Sleep() hängt.

Aber in jedem Fall zeigt Ihnen das Anhängen eines Debuggers, ob der Thread noch da ist und ob er wirklich hängengeblieben ist.

Andere Tipps

Wir haben Thread.Sleep ein paar Mal eingefügt, als die Datenbank verschwunden war und wir wieder auf 3-GB-Protokolldateien voller Datenbankverbindungsfehler zurückkamen.

Ich denke, eine bessere Option wäre es, dafür zu sorgen, dass Ihr Protokollierungssystem Duplikate abfängt, sodass es so etwas wie „Die vorherige Nachricht wurde N-mal wiederholt“ schreiben könnte.

Angenommen, ich habe eine Standardnotiz darüber geschrieben, wie Sie Ihre Verbindung im letztmöglichen Moment öffnen und zum frühestmöglichen Zeitpunkt schließen sollten, anstatt eine potenziell große Funktion auf die Art und Weise zu überspannen, wie Sie es getan haben (aber vielleicht ist das ein Artefakt). Ihres demonstrativen Codes und Ihre Anwendung ist tatsächlich richtig geschrieben).

Wenn Sie sagen, dass der von Ihnen beschriebene Fehler gemeldet wird, meinen Sie das auch so dieser Handler meldet den Fehler?Der Grund dafür, dass es mir nicht klar ist, ist, dass Sie im Codeausschnitt sagen: „Etwas ist schief gelaufen“, aber Sie haben das in Ihrer Beschreibung nicht gesagt;Ich möchte nicht, dass dies etwas so Dummes ist, da die Ausnahme woanders abgefangen wird und der Code irgendwo anders als im Ruhezustand hängen bleibt.

Ich hatte genau das gleiche Problem.Das Verschieben der Sleep-Zeile außerhalb des Ausnahmehandlers hat das Problem für mich behoben, wie folgt:

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

Das Unterbrechen von Threads scheint im Kontext eines Ausnahmehandlers nicht zu funktionieren.

Haben Sie es versucht? Monitor.Puls (Stellen Sie sicher, dass Ihr Thread die Thread-Verwaltung verwendet, bevor Sie dies ausführen.), um den Thread dazu zu bringen, etwas zu tun?Wenn das funktioniert, müssen Sie sich etwas genauer mit Ihrer Threading-Logik befassen.

Aus dem von Ihnen geposteten Code geht nicht klar hervor, dass das System nach dem Auslösen einer Ausnahme definitiv neu gestartet werden kann – z. B.Wenn die Ausnahme von doStuff() kommt, kehrt der Kontrollfluss (nach der 10-minütigen Wartezeit) zu openConnection() zurück, ohne jemals closeConnection() zu durchlaufen.

Aber wie andere bereits gesagt haben, schließen Sie einfach einen Debugger an und finden Sie heraus, wo er sich tatsächlich befindet.

Versuchen Sie Thread.Sleep(10 * 60 * 1000)

Ich habe nie ganz herausgefunden, was los war, aber es schien mit ThreadInterruptedExceptions zusammenzuhängen, die während des 10-minütigen Ruhezustands ausgelöst wurden, also habe ich den Code wie folgt geändert:

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);
    }
  }
}

Abgesehen davon, dass speziell die ThreadInterruptedException abgefangen wird, fühlt sich dies einfach sicherer an, da der gesamte Ruhezustand innerhalb eines Try-Blocks erfolgt, sodass alles Unerwartete, was passiert, protokolliert wird.Ich werde diese Antwort aktualisieren, wenn ich jemals mehr herausfinde.

Bin darüber gestolpert, als ich nach einem eigenen Thread.Sleep-Problem gesucht habe.Das mag damit zusammenhängen oder auch nicht, aber wenn Ihr doSomething() eine Ausnahme auslöst, wird closeDatabaseConnections() nicht passieren, was ein gewisses Potenzial für Ressourcenlecks birgt.Ich würde das in einen „finally“-Block einfügen.Nur etwas zum Nachdenken.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top