github.com/gitbundle/modules@v0.0.0-20231025071548-85b91c5c3b01/graceful/server_hooks.go (about)

     1  // Copyright 2023 The GitBundle Inc. All rights reserved.
     2  // Copyright 2017 The Gitea Authors. All rights reserved.
     3  // Use of this source code is governed by a MIT-style
     4  // license that can be found in the LICENSE file.
     5  
     6  package graceful
     7  
     8  import (
     9  	"os"
    10  	"runtime"
    11  
    12  	"github.com/gitbundle/modules/log"
    13  )
    14  
    15  // awaitShutdown waits for the shutdown signal from the Manager
    16  func (srv *Server) awaitShutdown() {
    17  	select {
    18  	case <-GetManager().IsShutdown():
    19  		// Shutdown
    20  		srv.doShutdown()
    21  	case <-GetManager().IsHammer():
    22  		// Hammer
    23  		srv.doShutdown()
    24  		srv.doHammer()
    25  	}
    26  	<-GetManager().IsHammer()
    27  	srv.doHammer()
    28  }
    29  
    30  // shutdown closes the listener so that no new connections are accepted
    31  // and starts a goroutine that will hammer (stop all running requests) the server
    32  // after setting.GracefulHammerTime.
    33  func (srv *Server) doShutdown() {
    34  	// only shutdown if we're running.
    35  	if srv.getState() != stateRunning {
    36  		return
    37  	}
    38  
    39  	srv.setState(stateShuttingDown)
    40  
    41  	if srv.OnShutdown != nil {
    42  		srv.OnShutdown()
    43  	}
    44  	err := srv.listener.Close()
    45  	if err != nil {
    46  		log.Error("PID: %d Listener.Close() error: %v", os.Getpid(), err)
    47  	} else {
    48  		log.Info("PID: %d Listener (%s) closed.", os.Getpid(), srv.listener.Addr())
    49  	}
    50  }
    51  
    52  func (srv *Server) doHammer() {
    53  	defer func() {
    54  		// We call srv.wg.Done() until it panics.
    55  		// This happens if we call Done() when the WaitGroup counter is already at 0
    56  		// So if it panics -> we're done, Serve() will return and the
    57  		// parent will goroutine will exit.
    58  		if r := recover(); r != nil {
    59  			log.Error("WaitGroup at 0: Error: %v", r)
    60  		}
    61  	}()
    62  	if srv.getState() != stateShuttingDown {
    63  		return
    64  	}
    65  	log.Warn("Forcefully shutting down parent")
    66  	for {
    67  		if srv.getState() == stateTerminate {
    68  			break
    69  		}
    70  		srv.wg.Done()
    71  
    72  		// Give other goroutines a chance to finish before we forcibly stop them.
    73  		runtime.Gosched()
    74  	}
    75  }