2019-06-07 03:10
浏览 102


I am writing a web server in Go using the standard library net/http package that makes use of systemd socket activation.

I have the basics working such that the server is started the first time a connection is made to the listening socket, and I can perform a graceful shutdown when signalled (i.e. so systemctl stop will work without cutting off active requests).

What I would like is for the server to automatically exit when it has been idle for some period of time. Something like the following:

  1. when the last active request completes, start a timer for say 30 seconds.
  2. if any new request arrives during that period, stop the timer.
  3. if the timer expires, perform a graceful shutdown.

The idea being to release the resources the server was using, in the knowledge that systemd will start us again when a new client turns up.

It's parts (1) and (2) that I'm not sure about. Ideally I'd like a solution that doesn't involve modifying all the registered handlers too.

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

1条回答 默认 最新

  • dongmiao4733
    dongmiao4733 2019-06-08 08:14

    Using @CeriseLimón's suggestion, the following helper type seems to do the trick:

    type IdleTracker struct {
        mu     sync.Mutex
        active map[net.Conn]bool
        idle   time.Duration
        timer  *time.Timer
    func NewIdleTracker(idle time.Duration) *IdleTracker {
        return &IdleTracker{
            active: make(map[net.Conn]bool),
            idle:   idle,
            timer:  time.NewTimer(idle),
    func (t *IdleTracker) ConnState(conn net.Conn, state http.ConnState) {
        oldActive := len(
        switch state {
        case http.StateNew, http.StateActive, http.StateHijacked:
  [conn] = true
            // stop the timer if we transitioned to idle
            if oldActive == 0 {
        case http.StateIdle, http.StateClosed:
            delete(, conn)
            // Restart the timer if we've become idle
            if oldActive > 0 && len( == 0 {
    func (t *IdleTracker) Done() <-chan time.Time {
        return t.timer.C

    Assigning its ConnState method to the server's ConnState member will track whether the server is busy, and signal us when we've been idle for the requested amount of time:

    idle := NewIdleTracker(5 * time.Second)
    server.ConnState = idle.ConnState
    go func() {
        if err := server.Shutdown(context.Background()); err != nil {
            log.Fatalf("error shutting down: %v
    ", err)
    点赞 评论