让go程序以后台进程或daemon方式运行方法探究

 更新时间:2024年01月25日 11:03:52   作者:磊丰 Go语言圈  
本文探讨了如何通过Go代码实现在后台运行的程序,最近我用Go语言开发了一个WebSocket服务,我希望它能在后台运行,并在异常退出时自动重新启动,我的整体思路是将程序转为后台进程,也就是守护进程(daemon)

引言

本文探讨了如何通过Go代码实现在后台运行的程序。最近我用Go语言开发了一个WebSocket服务,我希望它能在后台运行,并在异常退出时自动重新启动。我的整体思路是将程序转为后台进程,也就是守护进程(daemon)。它不处理具体的业务逻辑,而是再次使用相同的参数调用自身,启动一个子进程来处理业务逻辑。守护进程监视子进程的状态,如果子进程退出,则再次启动一个新的子进程。这样就能保证在服务异常终止时及时重启。

我在网上找到了一个开源库,github.com/sevlyar/go-daemon,它很方便地实现了在后台启动一个新的进程,但如果后台进程再次尝试作为另一个后台进程启动,会出现错误。

后来我阅读了源代码才发现:为了区分当前进程是父进程还是子进程,作者巧妙地设计了一个环境变量标识。正是因为这种识别策略,该库只能启动一次自身作为后台进程,无法连续启动自身为后台进程。

不过,这种使用环境变量来区分进程身份的思路给我启发很大。基于这个想法,我通过延伸和优化,最终实现了在保持参数不变的情况下连续启动自身为后台进程。我对作者表示敬意。

此外,我还找到了一些其他的库,它们的思路有所不同,主要通过添加特殊参数来标记进程身份。但是,这些方法并没有完美地解决让进程启动自身的问题,令我有些遗憾。

最终,我决定自己实现一个库来解决我的项目需求,并希望它是一个通用的库,可以快速方便地将用Go语言编写的服务程序转为后台运行或守护进程模式运行。本文总结了我在这次探索中的经验和收获。

后台运行和守护进程区别

首先,让我们区分一下两个概念:后台运行和守护进程。平常交流时,我们可能不太区分或区分不够清晰。在本文中,我想明确如下定义:

后台运行:指进程在操作系统中以非显示方式运行,没有与任何命令行终端或程序界面相关联。这种方式下运行的进程称为后台进程,比如没有与任何终端相关联的命令行程序进程。

守护进程:也称为守护进程,它首先以后台运行方式启动,然后还有额外的职责。在本文中,我的定义是守护进程可以监视Go服务程序进程的状态,如果异常退出,可以自动重新启动。这样守护进程可以确保服务程序一直在后台运行,即使它在某些情况下崩溃或意外终止。

接下来,我将介绍如何使用Go代码来实现在后台运行的程序,并将其转化为一个守护进程。

后台运行程序

要将Go程序在后台运行,可以使用一些操作系统级别的方法。以下是一种简单的方法:

package main
import (
    "fmt"
    "os"
    "os/exec"
    "syscall"
)
func main() {
    if os.Getppid() != 1 {
        cmd := exec.Command(os.Args[0])
        cmd.Start()
        fmt.Println("Background process ID:", cmd.Process.Pid)
        os.Exit(0)
    }
    // 在这里写入具体的业务逻辑代码
    fmt.Println("Running in background...")
    select {}
}

在上面的代码中,我们首先使用os.Getppid()函数获取当前进程的父进程ID。如果父进程不是1,说明当前进程不是守护进程,而是从终端启动的。在这种情况下,我们创建一个新的命令,使用相同的参数再次启动程序,并在后台运行。我们打印出新进程的PID,并退出初始进程。

如果进程的父进程是1,那么说明当前进程已经是守护进程了,我们可以在此处写入具体的业务逻辑代码。

使用这种方法,我们可以确保程序在后台运行,而且还可以检查是否已经启动了一个后台进程。

守护进程

将程序转化为守护进程需要额外的步骤,我们需要创建一个监听子进程状态的循环,并在子进程异常退出时重新启动它。以下是一个简单的守护进程实现:

package main
import (
    "fmt"
    "os"
    "os/exec"
    "syscall"
)
func main() {
    if os.Getppid() != 1 {
        cmd := exec.Command(os.Args[0])
        cmd.Start()
        fmt.Println("Background process ID:", cmd.Process.Pid)
        os.Exit(0)
    }
    // 在这里写入具体的业务逻辑代码
    fmt.Println("Running in background...")
    for {
        cmd := exec.Command(os.Args[0])
        cmd.Start()
        exitCh := make(chan error)
        go func() {
            exitCh <- cmd.Wait()
        }()
        err := <-exitCh
        if err != nil {
            fmt.Println("Process exited with error:", err)
        } else {
            fmt.Println("Process exited successfully")
        }
        select {
        case <-exitCh:
        default:
        }
    }
}

在上面的代码中,我们添加了一个循环,用于监听子进程的状态。在每次子进程退出之后,我们使用相同的参数再次启动守护进程,并重新开始监听。这样就可以确保服务程序在异常退出时能够自动重新启动。

这只是一个简单的守护进程实现,你可以根据自己的需求进行扩展和优化。

以上就是让go程序以后台进程或daemon方式运行方法探究的详细内容,更多关于go以后台进程daemon方式运行的资料请关注脚本之家其它相关文章!

相关文章

  • Go项目编写Makefile规则文件概述

    Go项目编写Makefile规则文件概述

    这篇文章主要为大家介绍了Go项目编写Makefile文件规则概述,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步早日升职加薪
    2022-04-04
  • Go语言运算符的具体使用

    Go语言运算符的具体使用

    本文介绍了Go语言中常用的运算符类型及其使用方法,主要内容包括: 算术运算符,关系运算符,逻辑运算符,位运算符,每种运算符都通过表格形式展示了具体功能,感兴趣的可以了解一下
    2026-06-06
  • go语言实现一个简单的http客户端抓取远程url的方法

    go语言实现一个简单的http客户端抓取远程url的方法

    这篇文章主要介绍了go语言实现一个简单的http客户端抓取远程url的方法,实例分析了Go语言http操作技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-03-03
  • go-micro微服务domain层开发示例详解

    go-micro微服务domain层开发示例详解

    这篇文章主要为大家介绍了go-micro微服务domain层开发示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-01-01
  • Go中gin框架的*gin.Context参数常见实用方法

    Go中gin框架的*gin.Context参数常见实用方法

    *gin.Context是处理HTTP请求的核心,ctx代表"context"(上下文),它包含了处理请求所需的所有信息和方法,例如请求数据、响应构建器、路由参数等,这篇文章主要介绍了Go中gin框架的*gin.Context参数常见实用方法,需要的朋友可以参考下
    2024-07-07
  • Go 语言中和类型Sum Types的创新实现方案详解

    Go 语言中和类型Sum Types的创新实现方案详解

    本文介绍了Go语言中如何通过ProjectionStructs和SafeUnsafeConversion来实现和类型(SumTypes),该方案通过内存布局相同的多个结构体投影同一块数据,实现零自定义编解码、编译时类型安全和IDE自动补全友好,感兴趣的朋友跟随小编一起看看吧
    2026-02-02
  • Golang栈结构和后缀表达式实现计算器示例

    Golang栈结构和后缀表达式实现计算器示例

    这篇文章主要为大家介绍了Golang栈结构和后缀表达式实现计算器示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-07-07
  • golang语法使用的注意事项

    golang语法使用的注意事项

    这篇文章主要给大家介绍了关于golang语法使用的一些注意事项,Golang是一种静态类型的编程语言,它支持基本的数据类型,包括整型、浮点型、布尔型、字符串型,需要的朋友可以参考下
    2023-07-07
  • Go语言利用泛型封装常见的Map操作

    Go语言利用泛型封装常见的Map操作

    Go 语言在 1.18 版本中引入了泛型,这是 Go 语言发展的一个重要里程碑,它极大地增强了语言的表达能力和灵活性,本文将通过泛型实现封装常见的Map操作,感兴趣的可以了解下
    2025-02-02
  • golang之数组切片的具体用法

    golang之数组切片的具体用法

    本文主要介绍了golang之数组切片的具体用法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-07-07

最新评论