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

VCR.NET 4.3: Aufgaben im Aufzeichnungsplan

Manchmal sind es einfach die kleinen Dinge, die nerven. So gab es im Aufzeichnungsplan zwei Schalter, um die Aufgaben für die Aktualisierung von Programmzeitschrift und Quellen (aka Sendersuchlauf) in den Plan einzublenden. Gerade die Beschriftung „Programmzeitschrift“ führte selbst bei mir dazu, dass ich diesen Schalter betätigt habe, wenn ich eigentlich eine neue Aufzeichnung anlegen wollte. In VCR.NET 4.3 gibt es nun einen Schalter für beide Arten von periodischen Hintergrundaufgaben, der zudem deutlich anders beschriftet ist. Ich hoffe, das hilft zumindest mir 🙂

Aufgaben im Aufzeichnungsplan

Wie immer viel Spaß

Jochen

VCR.NET 4.3: Aktuelle Uhrzeit in laufender Aufzeichnung

Bei einer laufenden Aufzeichnung wird in die Überlappanzeige von programmierter Zeit und Senderzeit aus der Programmzeitschrift nun ein kleiner Balken eingeblendet, der die aktuelle Uhrzeit repräsentiert. Somit erhält man einen schnellen Überblick über den Stand der Aufzeichnung – auch wenn man den Programmzeitschriften nicht wirklich glauben sollte.

Aktuelle Uhrzeit

Viel Spaß

Jochen

VCR.NET Issue Tracking in GitHub

Ich habe mal angefangen meine privaten ToDo Listen für DVB.NET und VCR.NET als Issues auf GitHub einzustellen – es besteht aber kein Anspruch auf Vollständigkeit!

Die Vergangenheit und vor allem der Anfang dieses Jahres hat gezeigt, dass eine Zeitplanung für meine privaten Projekte kaum möglich ist – dieses Jahr bisher vor allem beruflich bedingt, es sind aber noch private Dinge offen. Daher macht das Erstellen der Liste an sich auch keine Aussage darüber, was wirklich in die nächste Version (im Moment VCR.NET 4.3) aufgenommen wird. Allerdings habe ich schon mal mutig die Punkte dem Milestone 4.3 zugeordnet, die ich mir (in diesem Sinne) fest vorgenommen habe.

Zum Glück ist im Moment kein echter Show-Stopper bekannt, darum gehe ich das auch etwas ruhiger an.

Vielleich so als einfache Übersicht für alle Anwender

Jochen

ASP.NET Anwendungen über VCR.NET 4.3 anbieten

Der VCR.NET Recording Service hat einen auf der ASP.NET 4.5.1 Laufzeitumgebung basierenden integrierten Web Server, über den REST Dienste und der primäre Web Client angeboten werden – üblicherweise verfügbar über http://localhost/VCR.NET/default.html. Neu mit der Version 4.3 ist, dass nun weitere virtuelle Verzeichnisse über VCR.NET verfügbar gemacht werden können. Ähnlich wie im Internet Information Service bekommt jedes virtuelle Verzeichnis eine eigene .NET AppDomain zugeordnet, so dass eine gewisse Isolierung gegenüber den eigentlichen Aufgaben von VCR.NET garantiert ist. Natürlich ist diese Möglichkeit mit Bedacht einzusetzen, um den Kernbetrieb des VCR.NET Recording Service nicht zu gefährden und vor allem die Betriebsstabilität zu garantieren.

Beim Starten prüft VCR.NET 4.3ff, ob ein Unterverzeichnis Apps im Installationsverzeichnis existiert. Für jedes Unterverzeichnis darin wird ein gleichnamiges virtuelles Verzeichnis erstellt – diese darf natürlich namentlich nicht mit virtuellen Verzeichnissen anderer Web Server auf dem selben Rechner kollidieren, vor allem nicht mit denen des lokalen IIS. Existiert etwa ein Unterverzeichnis MediaDb, so kann nach dieses nach dem Starten vom VCR.NET als http://localhost/MediaDb/… verwendet werden.

Im Vorfeld hat sich zwar gezeigt, dass die ASP.NET Laufzeitumgebung innerhalb von VCR.NET kein vollwertiger Ersatz für einen IIS ist, aber zumindest habe ich für mich so eine sehr einfach und installationsarme Möglichkeit gefunden, Web Anwendungen anzubieten. Vielleicht hat sich ja der eine oder andere VCR.NET Anwender so etwas auch schon mal gewünscht, wer weiß.

Jochen