Starten eines Hintergrundprozesses



  • Hallo zusammen,

    für meine Tests möchte ich Datenbank + Server laufen lassen, dann Tests starten und anschließend Datenbank + Server wieder stoppen.

    CMake hat bereits Fixtures eingebaut:

    add_test(NAME setupServer COMMAND StartServer)
    add_test(NAME shutdownServer COMMAND StopServer)
    
    add_executable(ServerE2ETests)
    catch_discover_tests(ServerE2ETests PROPERTIES FIXTURES_REQUIRED Server)
    
    set_tests_properties(setupServer PROPERTIES FIXTURES_SETUP Server)
    set_tests_properties(shutdownServer PROPERTIES FIXTURES_CLEANUP Server)
    

    Die Exectuable setupServer läuft also jetzt vor meinen Tests und ist dafür verantwortlich Datenbank / Server zu starten.
    Die Anforderungen an das Skript (durch CMake) sind außerdem:

    • Das Skript muss enden und der Return Wert gibt an, ob das setup erfolgreich war oder nicht -> Daher der gestartete Server muss dann im Hintergrund laufen
    • Es darf keine Verbindung zum Terminal mehr offen sein? -> Etwas unklar. Aber basierend auf ein paar Experimenten kann es wohl sein, dass der Test nicht endet, wenn da noch irgendeine Pipe offen ist

    Das ganze habe ich versucht mit Boost.Process umzusetzen und sieht wie folgt bisher aus :

        bp::ipstream stream;
        bp::child serverProcess("@SERVER_EXECUTABLE@", (bp::std_out & bp::std_err) > stream, bp::std_in < bp::null);
    
        std::this_thread::sleep_for(std::chrono::seconds(2));
        stream.close();
    
        if(!serverProcess.running()) {
            std::cout << "Server not running\n";
            return -1;
        }
    
        std::ofstream file { "@PROCESS_ID_FILE@" };
        file << serverProcess.id();
    
        serverProcess.detach();
    

    Die Sachen in @@ werden durch CMake ersetzt. Daher das Skript startet den Server mit redirect in Stream. Wartet dann zwei Sekunden bis der Server hochgefahren ist und schließt dann den stream. Sofern der Server dann noch läuft, daher kein Fehler aufgtetreten ist, wird die PID in ne Datei geschrieben und der Server Prozess Detached.

    Soweit so gut: Läuft prima auf Linux und leider nicht wirklich auf Windows 😕

    Das Verhalten ist aktuell, dass er eine Konsole öffnet in der das StartServer Programm ausgeführt wird und bei Beenden des Programmes die Konsole aber offen bleibt. Entferne ich den redirect oben aus dem Programm kriege ich auch Output von meinem Server, das Terminal bleibt auch hier offen.
    Das scheint CMake wohl nicht so zu mögen und erkennt daher nicht, dass das StartServer Skript fertig ist.

    Im Code von Boost.Process ein bisschen geschaut, habe ich folgendes gefunden:
    https://github.com/boostorg/process/blob/develop/include/boost/process/detail/windows/executor.hpp#L195

    Ich habe für die creation flags (weiter oben) einfach mal 0x00000008 eingetragen, das steht laut https://docs.microsoft.com/en-us/windows/win32/procthread/process-creation-flags für DETACHED_PROCESS.
    Jetzt schließt sich zumindest die Konsole nach dem Ausführen von StartServer. Mit Cmake geht es aber trotzdem nicht. Manchmal bleibt er hängen, manchmal kommt die Fehlermeldung aus dem Skript "Server not running".
    Wenn ich hier jetzt aber auch das redirect komplett entferne, dann geht es plötzlich einwandfrei.

    Ich verstehe nicht wirklich, was hier vorgeht. Welchen Einfluss was genau hier hat, entschließt sich irgendwie jeglicher Logik bei mir.
    Zugegebnermaßen habe ich aber von Windows und auch wie das mit den Pipes etc. geht keine Ahnung.

    • Ist das anpassen der Flags oben wirklich notwendig? Ist das ein Bug in Boost?
    • Was hat es mit den Pipes auf sich? -> Auf Linux muss ich das redirecten, sonst geht es nicht ... auf Windows darf ich es nicht redirecten, sonst geht es nicht?


  • Kleiner Bump nochmal, in der Hoffnung, dass mir jemand bei Teilaspekten davon helfen kann 🙂



  • Was spricht dagegen alles in einen Docker Container zu verfrachten und Datenbank und Server über ein docker-compose file zu starten?



  • @Leon0402 sagte in Starten eines Hintergrundprozesses:

    Wenn ich hier jetzt aber auch das redirect komplett entferne, dann geht es plötzlich einwandfrei.

    Versuch mal eine Umleitung in ein File. Ist sowieso besser wenn die Daten verfügar sind wenn ein Test fehlgeschlagen ist und man rausfinden will wieso.

    Das Problem könnte einfach sein dass du den Output in einen Stream umleitest, den du dann schliesst bevor der Server-Prozess terminiert hat. Wenn der Prozess dann da noch was reinschreiben möchte, könnte ich mir vorstellen dass Dinge passieren die zu allem möglichen unerwünschten Verhalten führen.



  • @axels sagte in Starten eines Hintergrundprozesses:

    Was spricht dagegen alles in einen Docker Container zu verfrachten und Datenbank und Server über ein docker-compose file zu starten?

    Das mein Server dann nicht auf der Zielplattform läuft und der Test sinnlos ist 🙂

    @hustbaer sagte in Starten eines Hintergrundprozesses:

    Versuch mal eine Umleitung in ein File. Ist sowieso besser wenn die Daten verfügar sind wenn ein Test fehlgeschlagen ist und man rausfinden will wieso.
    Das Problem könnte einfach sein dass du den Output in einen Stream umleitest, den du dann schliesst bevor der Server-Prozess terminiert hat. Wenn der Prozess dann da noch was reinschreiben möchte, könnte ich mir vorstellen dass Dinge passieren die zu allem möglichen unerwünschten Verhalten führen

    Guter Punkt. Meine Idee war hier ursprünglich: Printe alles direkt aus bis überprüft wird, dass der Server noch läuft (= Erfolgreiches Setup).
    Sonstige Fehler dann im echten Prinzip werden sowieso (zusätzlich geloggt).
    Was ich statt Stream schließen vlt. eher will ist sowas wie Stream im nachinein nochmal umleiten auf null.

    Leider funktioniert aber weder der Vorschlag noch mein ursprünglicher fix, den ich im Eingangspost erwähnte.

    bp::child serverProcess("@SERVER_EXECUTABLE@", (bp::std_out & bp::std_err) > "test.log", bp::std_in < bp::null);
    bp::child serverProcess("@SERVER_EXECUTABLE@", bp::std_in < bp::null);
    

    In beiden Fällen scheint das Skript erst einmal zu tun, was es soll. Öffnet Konsole, startet alles, Konsole schließt wieder, Server + Datenbank läuft im Hintergrund.

    Wenn ich es über CTest ausführe, regristiert CTest aber weiterhin nicht, dass der Test schon fertig ist.

    Ich hatte das Problem mit der zweiten Variante (ohne redirect) eigentlich nicht, da hat alles super mindestens 20 mal hintereinander geklappt. Ich weiß nicht, was sich da jetzt geändert hat.

    Sofern du da spontan jetzt keine Idee hast, ist das jetzt vermutlich erstmal ein Fall für das CMake Forum. Da ist vlt. mehr Kenntniss über die Internas von CTest und warum der Test nicht stoppen will.



  • @Leon0402 sagte in Starten eines Hintergrundprozesses:

    Sofern du da spontan jetzt keine Idee hast

    Mir fällt erstmal nix mehr ein.


Log in to reply