Rumah > pembangunan bahagian belakang > Golang > Bagaimanakah saya boleh melaksanakan proses yang berjalan lama di Golang dan menanggalkannya daripada program saya sambil mengawal pengguna, mengubah hala output dan menghalangnya daripada menjadi zombi?

Bagaimanakah saya boleh melaksanakan proses yang berjalan lama di Golang dan menanggalkannya daripada program saya sambil mengawal pengguna, mengubah hala output dan menghalangnya daripada menjadi zombi?

Linda Hamilton
Lepaskan: 2024-10-28 04:17:30
asal
377 orang telah melayarinya

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?

Menjalankan Perintah dalam Go dan Mengeluarkannya daripada Proses

Masalah:

Anda ingin melaksanakan lama- menjalankan proses di Golang sambil memenuhi beberapa keperluan:

  • Ubah hala output standard proses ke fail
  • Kawal pengguna proses
  • Cegah proses daripada mati apabila program anda keluar
  • Elakkan proses menjadi zombi
  • Dapatkan PID proses berjalan

Percubaan Penyelesaian:

Anda telah mencuba penyelesaian menggunakan exec.Command tetapi ia tidak memenuhi semua keperluan, terutamanya apabila program anda menerima isyarat SIGTERM/SIGKILL.

Perkara Penting untuk Difahami:

Adalah penting untuk ambil perhatian bahawa anda tidak boleh menukar induk proses setelah ia dimulakan - hubungan ibu bapa-anak proses telah ditetapkan.

Perpustakaan Alternatif:

Daripada mencipta semula roda, anda disyorkan untuk menggunakan perpustakaan sedia ada yang menyelesaikan masalah ini. Perpustakaan berikut dicadangkan:

  • 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/

Contoh dengan 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>
Salin selepas log masuk

Contoh ini menggunakan go-reap untuk memulakan fungsi shell (Sh()) dan laksanakan arahan dalam shell tersebut. Ia menyediakan penuai untuk mengendalikan proses pembersihan kanak-kanak.

Dengan menggunakan perpustakaan yang bereputasi, anda boleh mengelakkan perangkap biasa dan memastikan aplikasi anda berkelakuan seperti yang dimaksudkan.

Atas ialah kandungan terperinci Bagaimanakah saya boleh melaksanakan proses yang berjalan lama di Golang dan menanggalkannya daripada program saya sambil mengawal pengguna, mengubah hala output dan menghalangnya daripada menjadi zombi?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

sumber:php.cn
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Artikel terbaru oleh pengarang
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan