code.gitea.io/gitea@v1.19.3/modules/graceful/server_hooks.go (about)

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