“Der Router ist kaputt – das sehe ich aber sofort”

Da es nun schon mal zum vierten Mal passiert ist und sowohl der Telekom-Support vor Ort als auch der 1&1 Support am Telefon an dieser Mär festhält, hier ein keiner Statusbericht zur Aufklärung. Ich verwende einen älteren Fritz!Box WLAN 7170 Router als Anschluss ans DSL. Ab und an (lobenswerter Weise selten, aber immerhin viermal in 2,5 Jahren) ist die Leitung auch mal extern gestört – letztens ein Kabelbruch im Verteiler.

Wenn dieser Fall eintritt und man führt einen Kaltstart (Netzstecker ziehen) des Routers durch, so passiert folgendes (Interpretation, AVM fragen geht leider nicht mehr, da das Modell nicht mehr unterstützt wird): die Box versucht den Aufbau der DSL Verbindung (WLAN LED an, Power LED blinkt im Doppeltakt). Je nach Zustand der DSL Verbindung macht sie das eine Weile, wobei zwischendurch auch mal ein Trennung und Re-Synchronisation probiert wird. Irgendwann ist wohl eine interne Schwelle von Fehlversuchen überschritten und der Router führt einen vollständigen Neustart durch. Danach geht das von vorne los.

Aber irgendwann wird es ganz spannend, dann ist der Router es wohl leid: nach einem Neustart wird KEIN neuer Versuch mehr unternommen, die DSL Verbindung herzustellen. WAN LED ist an, Power LED blinkt langsam UND ALLE ANDEREN LEDs blinken auch. Wenn aber alle LEDs blinken muss der Router (zumindest im oben aufgeführten Personenkreis) wohl kaputt sein – Diskussionen und Hinweise haben sich im Praxistest als völlig sinnlos erwiesen.

Tatsächlich muss man in diesem Zustand NACH der Reparatur der DSL Verbindung einen Kaltstart durchführen, da der Router dies von sich aus nicht macht. Interessant am Rande: irgendwie hat selbst das den Telekom Techniker vor Ort nicht wirklich überzeugt – obwohl der Router wieder einwandfrei arbeitete.

Also bitte liebe Supportmitarbeiter: wenn bei einem 7170 Router alles blinkt heißt das noch lange nicht, dass der Router kaputt ist. Vielleicht ist es ja wirklich ausnahmsweise 🙂 mal die Leitung! Leider gilt das umgekehrt aber nicht: wenn der Router mal tatsächlich kaputt ist, dann blinken evtl. auch alle LEDs. Aber immerhin ist es einen Versuch wert, die Leitung zu prüfen, oder?

Jochen

Yield und Reacquire in MSBuild Tasks

So richtig klar war mir die Verwendung dieser Methoden in einer eigenen MSBuild Task nicht – bis es dann knallte. Daher hier eine Anwendung mit meiner vermuteten Interpretation des Verhaltens, vielleicht hilft das ja dem einen oder anderen beim Verständnis und der Entwicklung eigener MSBuild Tasks.

Die Aufgabenstellung war eigentlich recht einfach und vermutlich auch nicht unüblich: eine größere Anzahl (800+) von Projekten soll mit MSBuild so schnell wie möglich auf einer eventuell potenten Maschine gebaut werden – im Test ein Dual-Xeon mit insgesamt 8 Kernen auf 2 Prozessoren mit zusätzlichem Hyper Threading, also insgesamt 16 logischen Kernen sowie einer SSD. Erst einmal sieht das aus wie eine triviale Aufgabe für die MSBuild Task und der BuildInParallel Option. Natürlich kann es nicht so einfach sein, da die Projekte untereinander abhängig sind und in einer bestimmten Reihenfolge gebaut werden müssen. Also schnell mal eine Visual Studio (2013) Solution On-The-Fly gemacht und die mit der MSBuild Task gebaut. Das geht im Prinzip auch aber leider nicht in dem konkreten Fall: neben C++ und C# Projekten gibt es besondere Projektarten, die Visual Studio und MSBuild nicht kennen. Theoretisch kann man das natürlich in die Infrastruktur von MSBuild einbringen (à la WiX et al), aber ich bin hier einen anderen Weg gegangen.

Ich verzichte auf die Details und erzähle nur das, worum es hier geht: die Projekte werden mit ihren Abhängigkeiten untereinander als MSBuild Items angelegt und einer MSBuild Dispatcher Task übergeben. Diese startet auf jedem MSBuild Knoten einen Build Vorgang mit einer speziellen Worker Task. Jede dieser Worker Tasks fordert bei dem Dispatcher ein Projekt zum Bauen an, baut dieses und teilt dem Dispatcher dann das Ergebnis mit. Der Dispatcher sorgt dafür, dass die Projekte in der korrekten Reihenfolge gebaut werden. Die Kommunikation zwischen Worker und Dispatcher ist über einen trivialen In-Process WCF Dienst und ein Named Pipe Binding geregelt.

Das funktionierte auch eine Weile und dann stand alles still – ein Deadlock. Was war passiert? Wenn ein Worker den Dispatcher nach einem neuen Projekt zur Bearbeitung fragt kann es sein, dass gerade keines zur Verfügung steht, weil abhängige Projekte noch in Berechnung sind. In diesem Fall wartet der WCF Aufruf des Workers, bis alle abhängigen Projekte abgearbeitet sind. Aus Sicht von MSBuild ist der MSBuild Node des Workers aber damit in Benutzung und kann nicht für andere Zwecke genutzt werden. In der besonderen Situation ergab es sich, dass alle Nodes bis auf einen (also hier: 15) auf eine besonders zentrale Abhängigkeit warteten, die von dem verbleibenden Node gebaut wurde. Dummerweise erforderte dieses Bearbeiten aber, dass MSBuild eine weiteren Node zur Abarbeitung anfordern musste und damit stand alles.

Hier kommt nun Yield ins Spiel: unmittelbar vor dem WCF Aufruf des Workers an den Dispatcher teilt die Dispatcher Task MSBuild via BuildEngine3.Yield() mit, dass der Node nun anderweitig beschäftigt ist. MSBuild kann dem Node nun andere Aufgaben zuordnen und der Deadlock ist weg. Wichtig ist, dass nach dem WCF Aufruf und sicher VOR dem nächsten MSBuild Zugriff des Workers ein BuildEngine3.Reacquire() erfolgt. Sollte auf dem Node zu diesem Zeitpunkt noch eine andere Aufgabe aktiv sein, so wird MSBuild den Reaquire Aufruf blockieren (das ist eine Vermutung, die aber durchaus Sinn macht), bis die andere Aufgabe abgeschlossen ist. Danach widmet sich der MSBuild Node wieder gänzlich unserer Worker Task.

Viel Spaß beim Coden

Jochen