首页  >  文章  >  后端开发  >  如何在 Go 中分离长时间运行的进程并避免僵尸?

如何在 Go 中分离长时间运行的进程并避免僵尸?

Linda Hamilton
Linda Hamilton原创
2024-11-01 07:51:31177浏览

How to Detach a Long-Running Process in Go and Avoid Zombies?

在 Go 中运行命令并将其与进程分离

问题:

你需要在 Go 中执行一个长时间运行的进程,并确保:

  • stdout 被重定向到一个文件。
  • 进程的用户受到控制。
  • 进程当你的程序退出时不会死亡。
  • 如果崩溃,进程不会变成僵尸。
  • 你获得正在运行的进程的 PID。

尝试的解决方案:

您尝试使用 cmd.Start() 和 cmd.Process.Release(),但它们并不能阻止程序退出时进程变成僵尸进程。你还希望进程尽可能独立,有自己的父PID、组PID等

解决方案:

你面临的问题是Linux 不允许您在进程启动后更改其父进程。如果你想要一个真正独立的进程,它需要由其他东西启动,例如 atd 或 systemd。

要解决僵尸和进程终止问题,你可以使用像 [go-reap] 这样的库(https://github.com/hashicorp/go-reap)。它提供了一个 Reaper 服务,可以自动收割孤立的子进程并报告其退出状态。

这是一个使用 go-reap 启动分离进程的示例:

<code class="go">package main

import (
    "context"
    "fmt"
    "os/exec"

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

func main() {
    // Start a Reaper service to reap orphaned processes.
    doneCh := make(chan struct{})

    ctx, cancel := context.WithCancel(context.Background())
    reaper := reap.NewReaper(cancel)
    go reaper.Run(ctx)
    defer reaper.Stop()

    // Execute a command in a detached process.
    cmd := exec.Command("my-long-running-command", "args")

    pid, err := reaper.Reap(cmd)
    if err != nil {
        fmt.Printf("Error reaping process: %v\n", err)
        return
    }

    fmt.Printf("PID of detached process: %v\n", pid)

    // Wait for the detached process to complete.
    exitStatus, err := reaper.WaitPid(pid)
    if err != nil {
        fmt.Printf("Error waiting for process: %v\n", err)
        return
    }

    fmt.Printf("Detached process exited with status: %v\n", exitStatus)

    // Stop the Reaper service when done.
    close(doneCh)
}</code>

通过使用 go-reap并在进程退出时收割该进程,可以确保它不会变成僵尸,并且可以跟踪它的退出状态。

以上是如何在 Go 中分离长时间运行的进程并避免僵尸?的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn