Heim > Backend-Entwicklung > Golang > Wie kann ich einen lang laufenden Prozess in Golang ausführen und ihn von meinem Programm trennen, während ich gleichzeitig den Benutzer kontrolliere, die Ausgabe umleite und verhindere, dass er zu einem Zombie wird?

Wie kann ich einen lang laufenden Prozess in Golang ausführen und ihn von meinem Programm trennen, während ich gleichzeitig den Benutzer kontrolliere, die Ausgabe umleite und verhindere, dass er zu einem Zombie wird?

Linda Hamilton
Freigeben: 2024-10-28 04:17:30
Original
378 Leute haben es durchsucht

How can I execute a long-running process in Golang and detach it from my program while controlling the user, redirecting output, and preventing it from becoming a zombie?

Einen Befehl in Go ausführen und vom Prozess trennen

Problem:

Sie möchten einen langen Befehl ausführen. Prozess in Golang ausführen und gleichzeitig mehrere Anforderungen erfüllen:

  • Standardausgabe des Prozesses in eine Datei umleiten
  • Kontrollieren Sie den Benutzer des Prozesses
  • Verhindern Sie, dass der Prozess abbricht, wenn Ihr Programm wird beendet
  • Vermeiden Sie, dass der Prozess zu einem Zombie wird
  • Besorgen Sie sich die PID des laufenden Prozesses

Lösungsversuch:

Sie haben versucht, eine Lösung mit exec.Command zu finden, diese erfüllt jedoch nicht alle Anforderungen, insbesondere wenn Ihr Programm SIGTERM/SIGKILL-Signale empfängt.

Wichtiger Punkt zum Verstehen:

Es ist wichtig zu beachten, dass Sie das übergeordnete Element eines Prozesses nicht mehr ändern können, sobald er gestartet wurde – die Eltern-Kind-Beziehung eines Prozesses ist festgelegt.

Alternative Bibliotheken:

Anstatt das Rad neu zu erfinden, empfiehlt es sich, eine vorhandene Bibliothek zu verwenden, die dieses Problem löst. Folgende Bibliotheken werden empfohlen:

  • https://github.com/hashicorp/go-reap
  • https://github.com/krallin/tini
  • https://busybox.net/
  • https://software.clapper.org/daemonize/
  • https://wiki.gentoo.org/wiki/OpenRC
  • https://www.freedesktop.org/wiki/Software/systemd/

Beispiel mit go-reap:

<code class="go">import (
    "fmt"
    "os"
    "os/exec"
    "strings"
    "sync"
    "time"

    "github.com/fatih/color"
    "github.com/hashicorp/go-reap"
)

func main() {

    if reap.IsSupported() {
        done := make(chan struct{})
        var reapLock sync.RWMutex
        pids := make(reap.PidCh, 1)

        errors := make(reap.ErrorCh, 1)
        go reap.ReapChildren(pids, errors, done, &reapLock)
        go report(pids, errors, done)

        // Here is where you would start your long-running process
        Sh()

        close(done)
    } else {
        fmt.Println("Sorry, go-reap isn't supported on your platform.")
    }
}

func report(pids reap.PidCh, errors reap.ErrorCh, done chan struct{}) {

    sprintf := color.New(color.FgWhite, color.Bold).SprintfFunc()

    for ;; {
        select {
        case pid := <-pids:
            println(sprintf(&quot;raeper pid %d&quot;, pid))
        case err := <-errors:
            println(sprintf(&quot;raeper er %s&quot;, err))
        case <-done:
            return
        }
    }
}

func Sh() {

    args := os.Args[1:]
    script := args[0:0]
    if len(args) >= 1 {
        if args[0] == &quot;-c&quot; {
            script = args[1:]
        }
    }
    if len(script) == 0 {
        fn.CyanBold(&quot;cmd: expecting sh -c 'foobar'&quot;)
        os.Exit(111)
    }

    var cmd *exec.Cmd
    parts, _ := shlex.Split(strings.Join(script, &quot; &quot;))
    if len(parts) >= 2 {
        cmd = fn.Merge(exec.Command(parts[0], parts[1:]...), nil)
    }
    if len(parts) == 1 {
        cmd = fn.Merge(exec.Command(parts[0]), nil)
    }

    // ... Here you can customize how the process is started and controlled

    if fn.IfEnv(&quot;HANG&quot;) {
        fn.CyanBold(&quot;cmd: %v\n      start&quot;, parts)
        ex := cmd.Start()
        if ex != nil {
            fn.CyanBold(&quot;cmd %v err: %s&quot;, parts, ex)
        }
        go func() {
            time.Sleep(time.Millisecond * 100)
            errw := cmd.Wait()
            if errw != nil {
                fn.CyanBold(&quot;cmd %v err: %s&quot;, parts, errw)
            } else {
                fn.CyanBold(&quot;cmd %v all done.&quot;, parts)
            }
        }()

        fn.CyanBold(&quot;cmd: %v\n      dispatched, hanging forever (i.e. to keep docker running)&quot;, parts)
        for {
            time.Sleep(time.Millisecond * time.Duration(fn.EnvInt(&quot;HANG&quot;, 2888)))
            fn.SystemCyan(&quot;/bin/ps&quot;, &quot;-e&quot;, &quot;-o&quot;, &quot;stat,comm,user,etime,pid,ppid&quot;)
        }

    } else {

        if fn.IfEnv(&quot;NOWAIT&quot;) {
            ex := cmd.Start()
            if ex != nil {
                fn.CyanBold(&quot;cmd %v start err: %s&quot;, parts, ex)
            }
        } else {

            ex := cmd.Run()
            if ex != nil {
                fn.CyanBold(&quot;cmd %v run err: %s&quot;, parts, ex)
            }
        }
        fn.CyanBold(&quot;cmd %v\n      dispatched, exit docker.&quot;, parts)
    }
}</code>
Nach dem Login kopieren

Dieses Beispiel verwendet go-reap, um eine Shell zu starten (Sh()-Funktion) und einen Befehl innerhalb dieser Shell auszuführen. Es richtet den Reaper so ein, dass er die Bereinigung der untergeordneten Prozesse übernimmt.

Durch die Verwendung einer seriösen Bibliothek können Sie häufige Fallstricke vermeiden und sicherstellen, dass sich Ihre Anwendung wie beabsichtigt verhält.

Das obige ist der detaillierte Inhalt vonWie kann ich einen lang laufenden Prozess in Golang ausführen und ihn von meinem Programm trennen, während ich gleichzeitig den Benutzer kontrolliere, die Ausgabe umleite und verhindere, dass er zu einem Zombie wird?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Neueste Artikel des Autors
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage