首页 > 其他分享 >Let'sGoFurther - Chapter 11: Graceful Shutdown

Let'sGoFurther - Chapter 11: Graceful Shutdown

时间:2024-11-18 21:30:49浏览次数:1  
标签:Chapter 11 00 app zzh Let time go runtime

 

zzh@ZZHPC:/zdata/Github/greenlight$ go run ./cmd/api
time=2024-11-18T19:49:43.864+08:00 level=INFO msg="database connection pool established"
time=2024-11-18T19:49:43.864+08:00 level=INFO msg="starting server" addr=:4000 env=development

Doing this should start a process with the name api on your machine. You can use the pgrep command to verify that this process exists, like so:

zzh@ZZHPC:~$ pgrep -l api
25711 api

Once that’s confirmed, go ahead and try sending a SIGKILL signal to the api process using the pkill command like so:

zzh@ZZHPC:~$ ps -ef | grep 25711
zzh        25711   25576  0 19:49 pts/0    00:00:00 /tmp/go-build3971774478/b001/exe/api
zzh        25976    9327  0 19:53 pts/1    00:00:00 grep --color=auto 25711
zzh@ZZHPC:~$ pkill -SIGKILL api

 

zzh@ZZHPC:/zdata/Github/greenlight$ go run ./cmd/api
time=2024-11-18T19:49:43.864+08:00 level=INFO msg="database connection pool established"
time=2024-11-18T19:49:43.864+08:00 level=INFO msg="starting server" addr=:4000 env=development
signal: killed

Feel free to repeat the same process, but sending a SIGTERM signal instead:

zzh@ZZHPC:~$ pgrep -l api
26248 api
zzh@ZZHPC:~$ pkill -SIGTERM api

 

zzh@ZZHPC:/zdata/Github/greenlight$ go run ./cmd/api
time=2024-11-18T19:56:08.698+08:00 level=INFO msg="database connection pool established"
time=2024-11-18T19:56:08.698+08:00 level=INFO msg="starting server" addr=:4000 env=development
signal: terminated

 

zzh@ZZHPC:~$ pgrep -l api
26488 api
zzh@ZZHPC:~$ pkill -SIGQUIT api

 

zzh@ZZHPC:/zdata/Github/greenlight$ go run ./cmd/api
time=2024-11-18T19:58:36.775+08:00 level=INFO msg="database connection pool established"
time=2024-11-18T19:58:36.775+08:00 level=INFO msg="starting server" addr=:4000 env=development
SIGQUIT: quit
PC=0x476461 m=0 sigcode=0

goroutine 0 gp=0xa18580 m=0 mp=0xa191e0 [idle]:
runtime.futex(0xa19320, 0x80, 0x0, 0x0, 0x0, 0x0)
        /home/zzh/.goenv/versions/1.23.0/src/runtime/sys_linux_amd64.s:557 +0x21 fp=0x7ffee822bb60 sp=0x7ffee822bb58 pc=0x476461
runtime.futexsleep(0x7ffee822bbd8?, 0x40da90?, 0x1e822bc08?)
        /home/zzh/.goenv/versions/1.23.0/src/runtime/os_linux.go:69 +0x30 fp=0x7ffee822bbb0 sp=0x7ffee822bb60 pc=0x432c10
runtime.notesleep(0xa19320)
        /home/zzh/.goenv/versions/1.23.0/src/runtime/lock_futex.go:170 +0x87 fp=0x7ffee822bbe8 sp=0x7ffee822bbb0 pc=0x40dc27
runtime.mPark(...)
        /home/zzh/.goenv/versions/1.23.0/src/runtime/proc.go:1866
runtime.stopm()
        /home/zzh/.goenv/versions/1.23.0/src/runtime/proc.go:2885 +0x8c fp=0x7ffee822bc18 sp=0x7ffee822bbe8 pc=0x43e16c
runtime.findRunnable()
        /home/zzh/.goenv/versions/1.23.0/src/runtime/proc.go:3622 +0xd5c fp=0x7ffee822bd90 sp=0x7ffee822bc18 pc=0x43fbdc
runtime.schedule()
        /home/zzh/.goenv/versions/1.23.0/src/runtime/proc.go:3995 +0xb1 fp=0x7ffee822bdc8 sp=0x7ffee822bd90 pc=0x440cb1
runtime.park_m(0xc0000061c0)
        /home/zzh/.goenv/versions/1.23.0/src/runtime/proc.go:4102 +0x1eb fp=0x7ffee822be20 sp=0x7ffee822bdc8 pc=0x4410cb
runtime.mcall()
        /home/zzh/.goenv/versions/1.23.0/src/runtime/asm_amd64.s:459 +0x4e fp=0x7ffee822be38 sp=0x7ffee822be20 pc=0x47266e

goroutine 1 gp=0xc0000061c0 m=nil [IO wait]:
runtime.gopark(0x0?, 0x0?, 0x0?, 0x0?, 0x0?)
        /home/zzh/.goenv/versions/1.23.0/src/runtime/proc.go:424 +0xce fp=0xc00014f9c8 sp=0xc00014f9a8 pc=0x46cbce
runtime.netpollblock(0x10?, 0x405be6?, 0x0?)
        /home/zzh/.goenv/versions/1.23.0/src/runtime/netpoll.go:575 +0xf7 fp=0xc00014fa00 sp=0xc00014f9c8 pc=0x431eb7
internal/poll.runtime_pollWait(0x78b3a509d6a0, 0x72)
        /home/zzh/.goenv/versions/1.23.0/src/runtime/netpoll.go:351 +0x85 fp=0xc00014fa20 sp=0xc00014fa00 pc=0x46bec5
internal/poll.(*pollDesc).wait(0xc000130400?, 0x10?, 0x0)
        /home/zzh/.goenv/versions/1.23.0/src/internal/poll/fd_poll_runtime.go:84 +0x27 fp=0xc00014fa48 sp=0xc00014fa20 pc=0x4c3c07
internal/poll.(*pollDesc).waitRead(...)
        /home/zzh/.goenv/versions/1.23.0/src/internal/poll/fd_poll_runtime.go:89
internal/poll.(*FD).Accept(0xc000130400)
...
exit status 2

 

 

package main

import (
    "fmt"
    "log/slog"
    "net/http"
    "time"
)

func (app *application) serve() error {
    srv := &http.Server{
        Addr:         fmt.Sprintf(":%d", app.config.port),
        Handler:      app.routes(),
        IdleTimeout:  time.Minute,
        ReadTimeout:  5 * time.Second,
        WriteTimeout: 10 * time.Second,
        ErrorLog:     slog.NewLogLogger(app.logger.Handler(), slog.LevelError),
    }

    app.logger.Info("starting server", "addr", srv.Addr, "env", app.config.env)

    return srv.ListenAndServe()
}

With that in place, we can simplify our main() function to use this new app.serve() method like so:

...
    // Call app.serve() to start the server.
    err = app.serve()
    if err != nil {
        logger.Error(err.Error())
        os.Exit(1)
    }
...

 

func (app *application) serve() error {
    srv := &http.Server{
        Addr:         fmt.Sprintf(":%d", app.config.port),
        Handler:      app.routes(),
        IdleTimeout:  time.Minute,
        ReadTimeout:  5 * time.Second,
        WriteTimeout: 10 * time.Second,
        ErrorLog:     slog.NewLogLogger(app.logger.Handler(), slog.LevelError),
    }

    // Start a background goroutine to catch signals.
    go func() {
        quit := make(chan os.Signal, 1)

        // Use signal.Notify() to listen for incoming SIGINT and SIGTERM signals and 
        // relay them to the quit channel.
        signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)

        // Read the signal from the quit channel. This code will block until a signal is received.
        s := <- quit

        app.logger.Info("caught signal", "signal", s.String())

        os.Exit(0)
    }()

    app.logger.Info("starting server", "addr", srv.Addr, "env", app.config.env)

    return srv.ListenAndServe()
}

 

zzh@ZZHPC:/zdata/Github/greenlight$ go run ./cmd/api
time=2024-11-18T20:35:36.803+08:00 level=INFO msg="database connection pool established"
time=2024-11-18T20:35:36.803+08:00 level=INFO msg="starting server" addr=:4000 env=development
^Ctime=2024-11-18T20:35:38.712+08:00 level=INFO msg="caught signal" signal=interrupt

 

zzh@ZZHPC:~$ pkill -SIGTERM api

 

zzh@ZZHPC:/zdata/Github/greenlight$ go run ./cmd/api
time=2024-11-18T20:36:52.920+08:00 level=INFO msg="database connection pool established"
time=2024-11-18T20:36:52.920+08:00 level=INFO msg="starting server" addr=:4000 env=development
time=2024-11-18T20:37:16.602+08:00 level=INFO msg="caught signal" signal=terminated

 

func (app *application) serve() error {
    srv := &http.Server{
        Addr:         fmt.Sprintf(":%d", app.config.port),
        Handler:      app.routes(),
        IdleTimeout:  time.Minute,
        ReadTimeout:  5 * time.Second,
        WriteTimeout: 10 * time.Second,
        ErrorLog:     slog.NewLogLogger(app.logger.Handler(), slog.LevelError),
    }

    // The shutdownError channel is used to receive any errors returned by the 
    // graceful Shutdown() function.
    shutdownError := make(chan error)

    // Start a background goroutine to catch signals.
    go func() {
        quit := make(chan os.Signal, 1)

        // Use signal.Notify() to listen for incoming SIGINT and SIGTERM signals and 
        // relay them to the quit channel.
        signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)

        // Read the signal from the quit channel. This code will block until a signal is received.
        s := <- quit

        app.logger.Info("shutting down server", "signal", s.String())

        ctx, cancel := context.WithTimeout(context.Background(), 30 * time.Second)
        defer cancel()

        shutdownError <- srv.Shutdown(ctx)
    }()

    app.logger.Info("starting server", "addr", srv.Addr, "env", app.config.env)

    err := srv.ListenAndServe()
    if !errors.Is(err, http.ErrServerClosed) {
        return err
    }

    err = <-shutdownError
    if err != nil {
        return err
    }

    app.logger.Info("stopped server", "addr", srv.Addr)

    return nil
}

 

func (app *application) healthcheckHandler(w http.ResponseWriter, r *http.Request) {
    data := envelope{
        "status": "available",
        "system_info": map[string]string{
            "environment": app.config.env,
            "version":     version,
        },
    }

    // Add a 4 second delay.
    time.Sleep(4 * time.Second)

    err := app.writeJSON(w, http.StatusOK, data, nil)
    if err != nil {
        app.serverErrorResponse(w, r, err)
    }
}

 

zzh@ZZHPC:~$ curl localhost:4000/v1/healthcheck & pkill -SIGTERM api
[1] 33833 (此行命令执行后立即出现)
zzh@ZZHPC:~$ {
    "status": "available",
    "system_info": {
        "environment": "development",
        "version": "1.0.0"
    }
}
(以上输出在命令执行后4秒出现。光标停在此,好几分钟后按回车键才出现下面一行)
[1]+  Done                    curl localhost:4000/v1/healthcheck
zzh@ZZHPC:~$

 

zzh@ZZHPC:/zdata/Github/greenlight$ go run ./cmd/api
time=2024-11-18T21:27:01.271+08:00 level=INFO msg="database connection pool established"
time=2024-11-18T21:27:01.271+08:00 level=INFO msg="starting server" addr=:4000 env=development
time=2024-11-18T21:27:02.114+08:00 level=INFO msg="shutting down server" signal=terminated(此行在 curl & pkill 命令执行后立即出现,因为该日志是在srv.Shutdown(ctx)之前)
time=2024-11-18T21:27:06.295+08:00 level=INFO msg="stopped server" addr=:4000 (此行在 curl & pkill 命令执行后4秒出现)

 

 

标签:Chapter,11,00,app,zzh,Let,time,go,runtime
From: https://www.cnblogs.com/zhangzhihui/p/18553720

相关文章

  • 2024.11.18 test
    AP9195[JOIOpen2016]JOIRIS逆天构造。直接看题解吧,主要是将列进行k染色,然后瞎jb做一下。BCF461EApplemanandaGame我们可以先建出SAM,设\(dp_{i,u}\)表示当前处理到\(i\)位,SAM上到\(u\)节点当前最小答案。由于答案具有单调性,考虑二分答案,也就是二分\(mid......
  • 20222411 2024-2025-1 《网络与系统攻防技术》实验六实验报告
    1.实验内容1.1实践内容(1)前期渗透①主机发现(可用Aux中的arp_sweep,search一下就可以use)②端口扫描:可以直接用nmap,也可以用Aux中的portscan/tcp等。③选做:也可以扫系统版本、漏洞等。(2)Vsftpd源码包后门漏洞(21端口)漏洞原理:在特定版本的vsftpd服务器程序中,被人恶意植入代码,当用......
  • 恶意代码分析入门--静态分析(chapter1_Lab01-01)
    恶意代码分析-工具收集-17bdw-博客园(cnblogs.com)实验环境:Lab1-1这个实验使用Lab01-01.exe和Lab01-01.dll文件,使用本章描述的工具和技术来获取关于这些文件的信息。操作环境操作场景:windowsxpsp3实验工具:PEiDv0.95Strings(新工具-在cmd窗口运行打印出目......
  • YOLOv11融合针对小目标FFCA-YOPLO中的FEM模块及相关改进思路
    YOLOv11v10v8使用教程:  YOLOv11入门到入土使用教程YOLOv11改进汇总贴:YOLOv11及自研模型更新汇总 《FFCA-YOLOforSmallObjectDetectioninRemoteSensingImages》一、模块介绍    论文链接:https://ieeexplore.ieee.org/document/10423050   ......
  • 11.18日每日收获
    const作用常量,不可被改变,如果是对指针,constchar*a,指的是指针a指向的变量不可被更改,a可变code作用是单片机中,将变量存储到FLASH中,读取速度变慢(相比于RAM),由于RAM空间小,故可将一些占用空间较大的数据,如链表等存放到CODE区域中static可以静态变量和静态函数,静态变量指的是不随函数......
  • CF715B Complete The Graph 题解
    Description给\(n\)点\(m\)边的无向图,\(L\),\(s\),\(t\)。修改\(m\)条边中边为\(0\)的边,使满足\(s,t\)的最短路长度是\(L\),且输出答案的时候边为\(0\)的边的权值必须在\([1,10^{18}]\)内。Solution考虑怎么判有无解。容易发现将所有未知边边权设为\(10^{18}\),......
  • 11.18 ~ 11.24
    11.18困......
  • Datasets is not supported in Complete output mode, only in Append output mode
    我们在使用pyspark,使用structureStreaming实时流的时候,创建出来的dataframe是流式的,不同于静态的df,流式的df使用的时候,不能用show()直接打印,而且使用sparkSQL的时候不可以在sql中使用开窗函数,并且还不可以使用join进行表关联举个栗子:执行以下代码会报错,因为在sql中使用了join......
  • 2024年11月17日 星期天 Go语言基础
    今日格言坚持每天进步一点点~一个人也可以是一个团队~学习全栈开发,做自己喜欢的产品~~Go语言的创始人Go语言的创始人有三位,分别是:RobertGriesemer:他参与开发了JavaHotSpot虚拟机。RobPike:他是Go语言项目的总负责人,曾是贝尔实验室Unix团队的成员,参与过Plan9、Inf......
  • ENGG1110 gameplay Elaborated
    ENGG1110ProjectChangelog Rev.DateDescriptionv1.22024/11/11P.10[5.22(b)]FixedPrintouttypoofprintGameBoard()P.13[5.5.1.1/candiesinfirstround.P.14[5.5.2]AddedthecheckingofemptycellsforTargetcellatswap.P.14[5.5.4]Addedclarification......