zoukankan      html  css  js  c++  java
  • 优雅的结束golang程序

    优雅的结束golang程序

    实现方式

    使用sync.WaitGroup配合context.WithCancel即可优雅的关掉

    	ctx, cancel := context.WithCancel(context.Background())
    	var wg sync.WaitGroup
    	signChan := make(chan os.Signal)
        signal.Notify(signChan, syscall.SIGINT) // ctrl+c
    	signal.Notify(signChan, syscall.SIGTERM) // kill
    
        go func() {
            force := false
            for {
                oscall := <-signChan
                if force {
                    os.Exit(1)
                }
                log.Infof("receive system call: %v", oscall)
                cancel()
                force = true
                log.Info("press ctrl+c again to force exit")
            }
        }()
    	tasks := make([]func(), 0)
    	tasks = append(tasks, func() {
    	    someCtx := ....
    	    someChan := ....
    	    for {
    	        select {
    	        case a := <- someChan:
    	            handle(a)
    	        case <-someCtx.Done():
    	            return
    	        case <-ctx.Done():
    	            return
    	        }
    	    }
    	    defer wg.Done()	
        })
        tasks = append(tasks, func() {
            for {
                // 模拟执行了其他耗时操作
                time.Sleep(10 * time.Second)
                if ctx.Err() != nil {
                    // cancel() called
                    return
                }
            }
        })
        // ... add more task
    	wg.Add(len(tasks))
    	for _, f := range tasks {
            go f()
        }
        log.Info("running")
        wg.Wait()
        log.Info("shutdown")
    

    代码里我们首先监听 SIGINT 和 SIGTERM, 当程序收到系统信号后调用cancel()通知子task该停止工作了。这里我们
    增加了一个force变量,保证可以通过两次ctrl+c命令强行终止程序。

    其中 SIGINT 响应ctrl+c命令。SIGTERM 响应系统kill命令(docker stop就是发送此signal)

    注意事项

    如何正常响应docker stop

    有时候会发现运行在docker中的go程序无法正确响应系统信号, 查看docker文档中提到了,docker stop会执行如下操作
    The main process inside the container will receive SIGTERM, and after a grace period, SIGKILL.
    注意这里提到了 main process,对于docker容器来说就是向pid为1的进程。很多时候我们的container command命令中运行的是一个脚本文件,类似
    sh /app/start.sh,文件内容类似如下

    echo "start app"
    /app/web
    

    这样的脚本执行结果就是 main process 是sh /app/start.sh,而不是我们的/app/web程序,此时要做的就是使用exec命令运行我们的程序

    echo "start app"
    exec /app/web
    

    这样我们的/app/web就是pid为1的进程了,也就可以正常的收到SIGTERM系统信号

  • 相关阅读:
    rtmp推流
    git 分支操作
    git 当前分支推送的新的仓库地址
    git 修改当前项目的仓库地址,项目迁移,仓库修改
    linux 服务器测试端口连通性
    ffmpeg linux 安装
    rtmp 命令详解
    slf4j和log4j源代码解析以及详解
    聊聊java基础,int值强制类型转换成byte
    应用中并发控制技巧
  • 原文地址:https://www.cnblogs.com/zihuyishi/p/14633528.html
Copyright © 2011-2022 走看看