ZhangZhihui's Blog  

 

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秒出现)

 

 

posted on   ZhangZhihuiAAA  阅读(5)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
 
点击右上角即可分享
微信分享提示