Go Daemon

一个用于 Go(golang)服务的守护程序包。「A daemon package for use with Go (golang) services with no dependencies」

Github星跟蹤圖

Go Daemon

一个用于 Go(golang)服务的守护程序包。

例子

最简单的例子(只需将 self 安装为守护进程即可)

package main
import (
    "fmt"
    "log"
    "github.com/takama/daemon"
)
func main() {
    service, err := daemon.New("name", "description", daemon.SystemDaemon)
    if err != nil {
        log.Fatal("Error: ", err)
    }
    status, err := service.Install()
    if err != nil {
        log.Fatal(status, "\nError: ", err)
    }
    fmt.Println(status)
}

实例

// Example of a daemon with echo service
package main
import (
    "fmt"
    "log"
    "net"
    "os"
    "os/signal"
    "syscall"
    "github.com/takama/daemon"
)
const (
    // name of the service
    name        = "myservice"
    description = "My Echo Service"
    // port which daemon should be listen
    port = ":9977"
)
// dependencies that are NOT required by the service, but might be used
var dependencies = []string{"dummy.service"}
var stdlog, errlog *log.Logger
// Service has embedded daemon
type Service struct {
    daemon.Daemon
}
// Manage by daemon commands or run the daemon
func (service *Service) Manage() (string, error) {
    usage := "Usage: myservice install | remove | start | stop | status"
    // if received any kind of command, do it
    if len(os.Args) > 1 {
        command := os.Args[1]
        switch command {
        case "install":
            return service.Install()
        case "remove":
            return service.Remove()
        case "start":
            return service.Start()
        case "stop":
            return service.Stop()
        case "status":
            return service.Status()
        default:
            return usage, nil
        }
    }
    // Do something, call your goroutines, etc

    // Set up channel on which to send signal notifications.
    // We must use a buffered channel or risk missing the signal
    // if we're not ready to receive when the signal is sent.
    interrupt := make(chan os.Signal, 1)
    signal.Notify(interrupt, os.Interrupt, os.Kill, syscall.SIGTERM)
    // Set up listener for defined host and port
    listener, err := net.Listen("tcp", port)
    if err != nil {
        return "Possibly was a problem with the port binding", err
    }

    // set up channel on which to send accepted connections
    listen := make(chan net.Conn, 100)
    go acceptConnection(listener, listen)

    // loop work cycle with accept connections or interrupt
    // by system signal
    for {
        select {
        case conn := <-listen:
            go handleClient(conn)
        case killSignal := <-interrupt:
            stdlog.Println("Got signal:", killSignal)
            stdlog.Println("Stoping listening on ", listener.Addr())
            listener.Close()
            if killSignal == os.Interrupt {
                return "Daemon was interruped by system signal", nil
            }
            return "Daemon was killed", nil
        }
    }
    // never happen, but need to complete code
    return usage, nil
}

// Accept a client connection and collect it in a channel
func acceptConnection(listener net.Listener, listen chan<- net.Conn) {
    for {
        conn, err := listener.Accept()
        if err != nil {
            continue
        }
        listen <- conn
    }
}

func handleClient(client net.Conn) {
    for {
        buf := make([]byte, 4096)
        numbytes, err := client.Read(buf)
        if numbytes == 0 || err != nil {
            return
        }
        client.Write(buf[:numbytes])
    }
}
func init() {
    stdlog = log.New(os.Stdout, "", log.Ldate|log.Ltime)
    errlog = log.New(os.Stderr, "", log.Ldate|log.Ltime)
}
func main() {
    srv, err := daemon.New(name, description, daemon.SystemDaemon, dependencies...)
    if err != nil {
        errlog.Println("Error: ", err)
        os.Exit(1)
    }
    service := &Service{srv}
    status, err := service.Manage()
    if err != nil {
        errlog.Println(status, "\nError: ", err)
        os.Exit(1)
    }
    fmt.Println(status)
}

服务配置文件

服务配置文件可以通过调用 GetTemplate() string 和 SetTemplate(string) 方法来获取或更新(MS Windows 除外)。模板将是一个默认的 Go Template("text/template")。

如果没有调用 SetTemplate,则在创建服务时将使用默认的模板内容。

变量 说明
Description 服务说明
Dependencies 服务依赖性
Name 服务名称
Path 服务可执行文件的路径
Args 服务可执行文件的参数


模板示例(linux 系统用)

[Unit]
Description={{.Description}}
Requires={{.Dependencies}}
After={{.Dependencies}}
[Service]
PIDFile=/var/run/{{.Name}}.pid
ExecStartPre=/bin/rm -f /var/run/{{.Name}}.pid
ExecStart={{.Path}} {{.Args}}
Restart=on-failure
[Install]
WantedBy=multi-user.target

Cron 例子

请看 examples/cron/cron_job.go

许可证

MIT Public License


主要指標

概覽
名稱與所有者takama/daemon
主編程語言Go
編程語言Go (語言數: 1)
平台Linux
許可證MIT License
所有者活动
創建於2014-08-02 04:10:34
推送於2023-12-01 07:26:13
最后一次提交2020-07-24 00:17:13
發布數52
最新版本名稱v1.0.0 (發布於 2020-07-24 00:17:13)
第一版名稱0.1.0 (發布於 2014-08-02 11:26:05)
用户参与
星數2k
關注者數60
派生數291
提交數304
已啟用問題?
問題數55
打開的問題數21
拉請求數31
打開的拉請求數7
關閉的拉請求數15
项目设置
已啟用Wiki?
已存檔?
是復刻?
已鎖定?
是鏡像?
是私有?

Go Daemon

A daemon package for use with Go (golang) services with no dependencies

GoDoc

Examples

Simplest example (just install self as daemon)

package main

import (
    "fmt"
    "log"

    "github.com/takama/daemon"
)

func main() {
    service, err := daemon.New("name", "description")
    if err != nil {
        log.Fatal("Error: ", err)
    }
    status, err := service.Install()
    if err != nil {
        log.Fatal(status, "\nError: ", err)
    }
    fmt.Println(status)
}

Real example

// Example of a daemon with echo service
package main

import (
    "fmt"
    "log"
    "net"
    "os"
    "os/signal"
    "syscall"

    "github.com/takama/daemon"
)

const (

    // name of the service
    name        = "myservice"
    description = "My Echo Service"

    // port which daemon should be listen
    port = ":9977"
)

//    dependencies that are NOT required by the service, but might be used
var dependencies = []string{"dummy.service"}

var stdlog, errlog *log.Logger

// Service has embedded daemon
type Service struct {
    daemon.Daemon
}

// Manage by daemon commands or run the daemon
func (service *Service) Manage() (string, error) {

    usage := "Usage: myservice install