douli1306
douli1306
2019-05-05 19:14
浏览 147
已采纳

发送自定义信号到curreng Golang过程

I'm creating a HTTP server using Go. And whenever I work on a database maintenance, I want the server to redirect all the traffic to "current working on maintenance" page.

Currently, this is done by secret admin page (eg. http://myhome/secret) but I'm wondering if this can be done with signal -similar to TERM signal, but temporarily redirect rather than actually terminate the process.

Eg.

/home/myhome> nohup startServer &
... 
/home/myhome> changeMyServerStatus "maintenance"

I assume there will be two executable.. "startServer" and "changeMyServerStatus"

So, this is similar to a service. (like reload) But, is this possible? If so, can you give me some hint please?

Thank you

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 邀请回答

1条回答 默认 最新

  • ds211107
    ds211107 2019-05-06 14:11
    已采纳

    As noted in the comments, signals may not be the best way to accomplish this. I’m assuming that you do want signals nonetheless.

    You can use the standard user signals: SIGUSR1 to enable maintenance and SIGUSR2 to disable it.

    Use os/signal to get notified of these signals and update program state:

    // Brief example code. Real code might be structured differently
    // (perhaps pack up maint and http.Server in one type MyServer).
    
    var maint uint32 // atomic: 1 if in maintenance mode
    
    func handleMaintSignals() {
        ch := make(chan os.Signal, 1)
        go func() { // FIXME: use Server.RegisterOnShutdown to terminate this
            for sig := range ch {
                switch sig { // FIXME: add logging
                case syscall.SIGUSR1:
                    atomic.StoreUint32(&maint, 1)
                case syscall.SIGUSR2:
                    atomic.StoreUint32(&maint, 0)
                }
            }
        }()
        signal.Notify(ch, syscall.SIGUSR1, syscall.SIGUSR2)
    }
    

    Have a middleware look at that state and respond accordingly:

    func withMaint(next http.Handler) http.Handler {
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            if atomic.LoadUint32(&maint) == 1 {
                http.Error(w, "Down for maintenance", http.StatusServiceUnavailable)
                return
            }
            next.ServeHTTP(w, r)
        })
    }
    

    You can apply this middleware on a per-route basis, or directly to the server’s root handler:

    func main() {
        handleMaintSignals()
        srv := http.Server{
            Addr:    ":17990",
            Handler: withMaint(http.DefaultServeMux),
        }
        srv.ListenAndServe()
    }
    

    You don’t need a second executable like changeMyServerStatus. Use your operating system’s tools to send signals, such as pkill:

    $ nohup myserver &
    
    $ curl http://localhost:17990/
    404 page not found
    
    $ pkill -USR1 myserver
    
    $ curl http://localhost:17990/
    Down for maintenance
    
    $ pkill -USR2 myserver
    
    $ curl http://localhost:17990/
    404 page not found
    

    But manually juggling nohup and pkill is tedious and error-prone. Instead, use a service manager such as systemd to manage your process. Systemd lets you send arbitrary signals with systemctl kill:

    systemctl kill -s SIGUSR1 myserver
    
    点赞 评论

相关推荐