Visual Studio 2008: Absturz ohne Vorwarnung - Fatal Execution Engine Error

Was ich nicht mag, ist wenn mir Visual Studio mitten in der Arbeit abschmiert… einfach so… bumm, weg! Das Event-Log sagt dann immer:

.NET Runtime version 2.0.50727.4927 - Fatal Execution Engine Error (6E61851A) (80131506)

Die Speicheradressen (in den Klammern hinten) variieren, der Effekt ist immer derselbe: ungespeicherte Arbeit geht verloren, wobei das Nervendste ist, dass VS sich die geöffneten Dateien nicht merkt. Änderungen gibt es selten so viele, dass ich mich groß ärgern müsste – dafür habe ich einen zu starken Reflex auf Strg+S zu drücken. Leider habe ich für diese Fehler noch keine Lösung gefunden.

Oliver


TDD != Unit-Test getrieben

Wer Testgetriebene-Entwicklung betreibt, muss nicht zwingend auch Unit-Test getrieben entwickeln.

Testgetrieben, sowohl in Greenfield also auch in Brownfield Projekten, ist für mich zunehmend Integrations oder Programmer-Test getrieben. Tatsächliche Unit-Tests (Testen von ageschlossenen Modulen) geraten zunehmend und nach Anwendungscharakter immer mehr in die Mindertheit.


WebService mit dotTrace Profilen

Ich hatte vor ein paar Tagen das Bedürfnis zu überprüfen, warum ein WebService so lange braucht, und welche Operationen das Bottleneck sind. Der WebService läuft bei mir lokal aufm IIS.

Dazu habe ich mir die Software dotTrace von JetBrains runtergeladen (Trial-Version). Ich habe mich ein wenig eingelesen, und im Forum gefragt, dann war der Rest recht einfach. “Local Computer” im Host-Menü eingeben. Beim nächsten “Internet Information Service” als Profiler kind auswählen, und schon kann es los gehen.

Ich habe dann den einen Windowsservice gestartet, der mit dem Webservice kommuniziert, den Profiler gestartet, und einen Snapshot gemacht. Das einzig etwas mühselige ist nun herauszufinden, wo sich genau die Aufrufe befinden, die einen selbst betreffen. Aber durch die Suche kann man bequem nach Funktionen und Klassen suchen, und findet schnell die richtigen Stellen.

(JetBrains hat es noch nicht geschafft, eine Doku dazu rauszubringen, da die 4.0 Version noch in der Beta ist.)

Happy Profiling.

Erweiterung: Hier gibt es noch eine Alternative: Direkt aus Visual Studio heraus das Profiling starten - mit dem WebService als Startup-Project.


SQL Server “Auto-Close” führt zu Time Outs & I/O Stress

Gerade erreichte uns eine Monitoring SMS weil eine Kundenseiten Down war. Ein kurze Überprüfung konnte das nicht bestätigen, jedoch der Event-Log:

Event-Log

Die ASP.NET Fehlerdetails sagen:

Exception information:
    Exception type: SqlException
    Exception message: Timeout expired.  The timeout period elapsed prior to completion of the operation or the server is not responding.

Doch wie kann das sein? Auch wenn eine Vielzahl von Seiten auf dem Server eingerichtet sind, ist der Dual-Quadcore mit 8 Gigabyte RAM kaum unter Last. Aufschluss aus welcher Richtung das Problem kommt, geben die Vielzahl von MSSQL$EXPRESS Events: “Starting up database 'XY'.”

Der Grund für das häufige Neustarten der Datenbank ist so erklären: Einige Kundeninstallation werden selten verwendet. Die Einstellung “Auto-Close” …

image

(Zeigt: “Database Properties”, rechte Maustaste auf die DB)

… wird der SQL-Server dazu veranlasst die Datenbank “herunterzufahren” und Resourcen frei zu geben. Das geschieht wenn der letzte Benutzer sich vom SQL Server abmeldet, in diesem Fall also wenn der Connection-Pool geschlossen wird, was geschieht wenn die Webseite herunterfährt, also der Worker-Process für einen Web-Application-Pool beendet wird,

IIS-Timout 

(IIS Connection-Pool Properties)

per Default nach 20 Minuten.

Durch unser Monitoring  werden jedoch in einem wiederkehrendem Intervall (@Mark, in welchem genau?) viele Seiten relativ zeitgleich aufgerufen und dadurch “neu gestartet” was dazu führt, dass viele Application-Pools und Datenbanken wieder “hochfahren” müssen. Die aktuelle Theorie ist, das dass I/O Stress verusacht und zum obigen Fehler führt. Selten (weniger als einmal im Monat) kommt es dann zu dieser Fehlermeldung: “SQL Server has encountered 1 occurrence(s) of I/O requests taking longer than 15 seconds to complete on file”, die eine Fehler SMS zur Folge hat und die nicht mehr auftreten sollte wenn der “Idel Time-out verlängert” wird und das SQL Server Close abgestellt ist.


Vorsicht bei String als Lock-Objekt

Wenn man denn unbedingt einen String als Lock-Objekt nutzen will und man sich davon überzeugt hat, nicht den Type eines gerade durch die Methode schwirrenden Objektes zu nutzen (das könnte ja jeder machen ;-)), dann sollte man auf jeden Fall an String.Intern(myLockString) denken!

Wo man kann, sollte man also weiterhin einen einfachen object-Lock nutzen:

   1: private static readonly object _lock = new object();

Aber man darf dann nicht vergessen, dass alle Threads, die auf den Code im Lock zugreifen von einem einzigen Lock bedient werden. Wenn man die Threads aber in Gruppen aufteilen kann, die unabhängig voneinander arbeiten können, ist diese Beschränkung zu scharf. Ich suchte also einen Weg, einen eindeutigen Lock für jede dieser Gruppen (hier: TranslationGroup) zu generieren, der von allen Instanzen geteilt wird. Der Gruppenidentifikator heißt hier _pageNameKey.

Beispiel:

   1: private const string _migrateLock = "9B90360AAF4342798A739DA2D85AF5AF"; // guid
   2:  
   3: private string _pageNameKey = ...; // can be the same in multiple parallel threads
   4:  
   5: public void Migrate(string oldGroupName, Dictionary<string, string> controlIdsOldToNew)
   6: {
   7:     lock (string.Intern(_migrateLock + _pageNameKey))
   8:     {
   9:         // do something not here that should not be done in parallel
  10:     }
  11: }

Ließe man in Zeile 7 das String.Intern(…) weg, würde bei jedem Aufruf der Methode ein neues String-Objekt generiert – was für dem Lock seine Existenzberechtigung raubt.

Gruß, Oliver

Technorati-Tags: ,,,

Foreign keys that create a cycle :-)

Gerade auf meinem Monitor gesehen, bei dem Versuch für eine MS-SQL Datenbank einen dump zu erzeugen…

circulare-f-keys

Nach dem Database-Publishing-Wizard gescheitert ist, hat SQLDUMP die Aufgabe mit Bravour gelöst :-)

SqlDump