golang進程啟動及監(jiān)控方式
golang進程啟動及監(jiān)控
- 守護進程(deamon):為任意進程創(chuàng)建守護進程,使進程脫離終端運行
- 監(jiān)控進程(forever):創(chuàng)建監(jiān)控重啟進程,使進程被殺死后能夠重啟
由于近期項目需要,使用go預研開發(fā)邊緣智能程序,因此就想著通過golang實現(xiàn)進程守護及進程監(jiān)控的功能,在golang程序中啟動子進程,有很好的封裝exec.Command,導入包為os/exec,本文主要以此種方式實現(xiàn),包含以下兩種實現(xiàn)方式。
1.1 以集成到業(yè)務代碼的方式實現(xiàn)
此方式是把相關代碼集成到我們需要監(jiān)控的進程代碼中,通過命令行參數(shù)來判斷是否啟用守護進程,其代碼如下所示:
test.go
package test
import (
"flag"
"fmt"
"os"
"os/exec"
"time"
)
func main() {
daemon := flag.Bool("deamon", false, "run in daemon and forever")
flag.Parse()
//判斷是否以守護進程的方式啟動
if *daemon {
runbydeamon(os.Args) //執(zhí)行deamon,由其啟動主程序
}
//業(yè)務主程序代碼
fmt.Println("start test Service")
}
//以deamon的方式啟動程序,并監(jiān)控進程
func runbydeamon(args []string) {
fmt.Printf("PID: %d PPID: %d ARG: %s\n", os.Getpid(), os.Getppid(), os.Args)
//去掉-deamon運行參數(shù),啟動主程序
for i := 0; i < len(args); {
if args[i] == "-deamon" && i != len(args)-1 {
args = append(args[:i], args[i+1:]...)
} else if args[i] == "-deamon" && i == len(args)-1 {
args = args[:i]
} else {
i++
}
}
//啟動子進程,去掉-deamon參數(shù)后,執(zhí)行程序,由于子程序無deamon參數(shù),因此會直接執(zhí)行業(yè)務代碼
for {
cmd := exec.Command(args[0], args[1:]...)
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err := cmd.Start()//開啟子進程
if err != nil {
fmt.Fprintf(os.Stderr, "start oasis erir [-] Error: %s\n", err)
return
}
fmt.Println("run oasis bydeamon,pid=", cmd.Process.Pid, ",ppid=", os.Getpid(), "args=", args, "time=", time.Now())
cmd.Wait() //阻塞等待進程退出
}
}
通過go buid編寫以后,執(zhí)行"test -deamon"后,由于帶有代碼會啟動兩個test進程,第一次啟動時由于帶有參數(shù)"-deamon",因此會調(diào)用runbydeamon,此函數(shù)會去掉-deamon參數(shù),再次以子進程的方式執(zhí)行"test",通過cmd.start()啟動子進程,子進程由于不帶"-deamon",會直接進入業(yè)務代碼實現(xiàn),這里會打?。?/p>
start test Service,守護進程有一個for循環(huán),一直在等待子進程退出,如果子進程異常退出,守護進程會再次把子進程進程拉起來并等待。
1.2 以單獨代碼的方式實現(xiàn)
上文實現(xiàn)方式,與業(yè)務代碼耦合,啟動時只需要帶有一個參數(shù)即可啟動守護進程和業(yè)務進程,啟動比較簡單,但是代碼與業(yè)務耦合在一起,這種寫法使得沒法復用守護進程,其實守護進程與業(yè)務進程沒有任何關系,大可提取出來,作為通用的守護進程程序,支持任務進程的后臺啟動和監(jiān)控,代碼如下:
deamon.go
package deamon
import (
"flag"
"fmt"
"os"
"os/exec"
"time"
)
func main() {
pcmd := flag.String("cmd", "", "run cmd in daemon and forever")
flag.Parse()
runbydeamon(*pcmd) //執(zhí)行deamon,由其啟動主程序
}
//以deamon的方式啟動程序,并監(jiān)控進程
func runbydeamon(args string) {
fmt.Printf("PID: %d PPID: %d ARG: %s\n", os.Getpid(), os.Getppid(), os.Args)
if cmd==""{
fmt.Println("cmd is null")
os.Exit(0)
}
//啟動子進程,既是去掉-deamon參數(shù)后,執(zhí)行程序,由于子程序無deamon參數(shù),因此會直接執(zhí)行業(yè)務代碼
for {
cmd := exec.Command(args[1], args[2:]...)
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err := cmd.Start()//開啟子進程
if err != nil {
fmt.Fprintf(os.Stderr, "start oasis erir [-] Error: %s\n", err)
return
}
fmt.Println("run oasis bydeamon,pid=", cmd.Process.Pid, ",ppid=", os.Getpid(), "args=", args, "time=", time.Now())
cmd.Wait() //阻塞等待進程退出
}
}
test.go
package test
import (
"flag"
"fmt"
)
func main() {
fmt.Println("start test Service")
}
以守護進程的方式啟動進程命令:
deamon -cmd “test”
如果執(zhí)行test要帶命令行,可直接作為deamon的命令行傳遞給test:
deamon -cmd “test” -c “config.yaml”
有關運行參數(shù)flag定義,可根據(jù)需要自行定義,這里僅是一個例子。
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
Golang中goto跳轉(zhuǎn)語句的實現(xiàn)
本文主要介紹了Golang中goto跳轉(zhuǎn)語句的實現(xiàn),包括標簽的定義、跳轉(zhuǎn)語句的使用、作用域限制、避免濫用的原因以及歷史遺留代碼中的使用情況,感興趣的可以了解一下2025-03-03
一文帶你玩轉(zhuǎn)Golang Prometheus Eexporter開發(fā)
本文分兩大塊,一是搞清楚prometheus四種類型的指標Counter,Gauge,Histogram,Summary用golang語言如何構造這4種類型對應的指標,二是搞清楚修改指標值的場景和方式,感興趣的可以了解一下2023-02-02
淺談Go語言不提供隱式數(shù)字轉(zhuǎn)換的原因
本文主要介紹了淺談Go語言不提供隱式數(shù)字轉(zhuǎn)換的原因,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2023-03-03

