golang daemon 进程 可处理信号

用go 开源库 GitHub - sevlyar/go-daemon: A library for writing system daemons in golang.实现守护进程

package main

import (
	"flag"
	"github.com/sevlyar/go-daemon"
	"log"
	"os"
	"syscall"
	"time"
)

var (
	signal = flag.String("s", "", `Send signal to the daemon:
  quit — graceful shutdown
  stop — fast shutdown
  reload — reloading the configuration file`)
)

func main() {
	flag.Parse()
    /*注册信号处理函数,这里可以增加我们自己的信号处理函数,自定义对应的handler函数*/
	daemon.AddCommand(daemon.StringFlag(signal, "quit"), syscall.SIGQUIT, termHandler)
	daemon.AddCommand(daemon.StringFlag(signal, "stop"), syscall.SIGTERM, termHandler)
	daemon.AddCommand(daemon.StringFlag(signal, "reload"), syscall.SIGHUP, reloadHandler)

	cntxt := &daemon.Context{
		PidFileName: "sample.pid",//存进程pid的文件
		PidFilePerm: 0644,
		LogFileName: "sample.log",//进程日志文件
		LogFilePerm: 0640,
		WorkDir:     "./",//切换工作目录
		Umask:       027,
		Args:        []string{"[go-daemon sample]"},//进程名
	}

	if len(daemon.ActiveFlags()) > 0 {
		d, err := cntxt.Search()
		if err != nil {
			log.Fatalf("Unable send signal to the daemon: %s", err.Error())
		}
		daemon.SendCommands(d)
		return
	}

	d, err := cntxt.Reborn()
	if err != nil {
		log.Fatalln(err)
	}
	if d != nil {
		return
	}
	defer cntxt.Release()

	log.Println("- - - - - - - - - - - - - - -")
	log.Println("daemon started")

	go worker()//启动主循环函数

	err = daemon.ServeSignals()//信号处理函数
	if err != nil {
		log.Printf("Error: %s", err.Error())
	}

	log.Println("daemon terminated")
}

var (
	stop = make(chan struct{})
	done = make(chan struct{})
)

func worker() {
LOOP:
	for {
        //do something 在这里实现我们的主体逻辑,理论上执行完休眠一秒
		time.Sleep(time.Second) // this is work to be done by worker.
		select {
		case <-stop:
			break LOOP
		default:
		}
	}
	done <- struct{}{}
}

func termHandler(sig os.Signal) error {
	log.Println("terminating...")
	stop <- struct{}{}
	if sig == syscall.SIGQUIT {
		<-done
	}
	return daemon.ErrStop
}

func reloadHandler(sig os.Signal) error {
	log.Println("configuration reloaded")
	return nil
}

go mod init daemon

go mod tidy 

go build daemon.go

然后就会生成 daemon可执行文件。

我在上面的代码中增加一个打印,来看是否是定时执行(睡眠一秒):

func worker() {
LOOP:
        for {
        //do something 在这里实现我们的主体逻辑,理论上执行完休眠一秒
        log.Println("this is a test")
                time.Sleep(time.Second) // this is work to be done by worker.
                select {
                case <-stop:
                        break LOOP
                default:
                }
        }
        done <- struct{}{}
}

我们看输出:

 结果如我们预期

 进程名也对应上了。

如果我们在这个代码中修改打印为如下代码,将会怎样


func worker() {
LOOP:
        for {
        //do something 在这里实现我们的主体逻辑,理论上执行完休眠一秒
        fmt.Println("this is a test")
                time.Sleep(time.Second) // this is work to be done by worker.
                select {
                case <-stop:
                        break LOOP
                default:
                }
        }
        done <- struct{}{}
}

使用fmt,当然需要在import中增加"fmt"。

结果如下:还是打印到sample.log中。

 

 具体原因我们可以先看一下/proc/110144/fd目录

 这下就可以明白,原来标准输出 2 就是sample.log文件。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在 Go 语言中,gRPC(Google Remote Procedure Call)是一个高性能、开源的 RPC 框架,它基于 HTTP/2 和 Protocol Buffers(protobuf)协议。当涉及到进程同步时,gRPC 提供了一种可靠的方式来协调客户端和服务器之间的通信,特别是在处理并发请求时。 gRPC 的进程同步主要通过以下几种机制: 1. **流(Streaming)**:gRPC 支持双向流,即客户端可以发送一系列消息给服务器,服务器也可以逐条响应。这种方式可以实现异步的进程同步,因为服务端不需要等待接收所有消息再作响应。 2. **WaitGroup**:客户端在发起请求后,可以通过 `sync.WaitGroup` 来管理多个操作。客户端在完成所有 gRPC 调用后调用 `wg.Done()`,服务器接收到请求后执行相应操作并在完成后调用 `wg.Done()`,这样整个 WaitGroup 就会等待所有操作完成。 3. **通道(Channel)**:Go 语言中的通道是进程间通信的重要手段。gRPC 可以利用通道在客户端和服务器之间传递数据,通过关闭通道或读取空通道来实现进程间的同步。 4. **Deadline/TIMEOUTs**:gRPC 调用默认设置有超时限制,如果服务器在规定时间内没有响应,客户端可以取消请求,实现流程控制。 5. **Server-side streaming** 和 **Client-side streaming**:这两种模式允许服务器主动向客户端推送数据,或者客户端连续发送数据。这提供了更精细的控制,可以根据业务需求调整进程同步。 相关问题-- 1. 在 gRPC 中,如何使用 WaitGroup 实现进程同步? 2. gRPC 通道在进程同步中的作用是什么? 3. 如何通过超时机制在 gRPC 中实现进程控制?

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值