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系统信号

  • 相关阅读:
    腾讯之困,QQ与微信各有各的烦恼
    Attribute(一)——提前定义特性
    假设有来生
    codeforces248(div1) B Nanami&#39;s Digital Board
    驳斥苹果“诊断后门论”,声援扎德尔斯基
    python批量下载色影无忌和蜂鸟的图片 爬虫小应用
    建筑建模学习笔记2——3DMax房屋框架建模
    【大话QT之十六】使用ctkPluginFramework插件系统构建项目实战
    javaObject类
    java基本类型和String之间的转换
  • 原文地址:https://www.cnblogs.com/zihuyishi/p/14633528.html
Copyright © 2011-2022 走看看