Merge pull request #11927 from jwhonce/issues/11921

Fix CI flake on time of shutdown for API service
This commit is contained in:
OpenShift Merge Robot
2021-10-12 21:08:10 +02:00
committed by GitHub
4 changed files with 31 additions and 20 deletions

View File

@ -93,7 +93,7 @@ func restService(flags *pflag.FlagSet, cfg *entities.PodmanConfig, opts entities
return err return err
} }
defer func() { defer func() {
if err := server.Shutdown(false); err != nil { if err := server.Shutdown(true); err != nil {
logrus.Warnf("Error when stopping API service: %s", err) logrus.Warnf("Error when stopping API service: %s", err)
} }
}() }()

View File

@ -5,9 +5,10 @@ import (
"os/signal" "os/signal"
"sync" "sync"
"syscall" "syscall"
"time"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus" logrusImport "github.com/sirupsen/logrus"
) )
var ( var (
@ -25,6 +26,7 @@ var (
// Ordering that on-shutdown handlers will be invoked. // Ordering that on-shutdown handlers will be invoked.
handlerOrder []string handlerOrder []string
shutdownInhibit sync.RWMutex shutdownInhibit sync.RWMutex
logrus = logrusImport.WithField("PID", os.Getpid())
) )
// Start begins handling SIGTERM and SIGINT and will run the given on-signal // Start begins handling SIGTERM and SIGINT and will run the given on-signal
@ -44,25 +46,31 @@ func Start() error {
go func() { go func() {
select { select {
case <-cancelChan: case <-cancelChan:
logrus.Infof("Received shutdown.Stop(), terminating!")
signal.Stop(sigChan) signal.Stop(sigChan)
close(sigChan) close(sigChan)
close(cancelChan) close(cancelChan)
stopped = true stopped = true
return return
case sig := <-sigChan: case sig := <-sigChan:
logrus.Infof("Received shutdown signal %v, terminating!", sig) logrus.Infof("Received shutdown signal %q, terminating!", sig.String())
shutdownInhibit.Lock() shutdownInhibit.Lock()
handlerLock.Lock() handlerLock.Lock()
for _, name := range handlerOrder { for _, name := range handlerOrder {
handler, ok := handlers[name] handler, ok := handlers[name]
if !ok { if !ok {
logrus.Errorf("Shutdown handler %s definition not found!", name) logrus.Errorf("Shutdown handler %q definition not found!", name)
continue continue
} }
logrus.Infof("Invoking shutdown handler %s", name)
logrus.Infof("Invoking shutdown handler %q", name)
start := time.Now()
if err := handler(sig); err != nil { if err := handler(sig); err != nil {
logrus.Errorf("Running shutdown handler %s: %v", name, err) logrus.Errorf("Running shutdown handler %q: %v", name, err)
} }
logrus.Debugf("Completed shutdown handler %q, duration %v", name,
time.Since(start).Round(time.Second))
} }
handlerLock.Unlock() handlerLock.Unlock()
shutdownInhibit.Unlock() shutdownInhibit.Unlock()

View File

@ -207,7 +207,7 @@ func (s *APIServer) setupSystemd() {
func (s *APIServer) Serve() error { func (s *APIServer) Serve() error {
s.setupPprof() s.setupPprof()
if err := shutdown.Register("server", func(sig os.Signal) error { if err := shutdown.Register("service", func(sig os.Signal) error {
return s.Shutdown(true) return s.Shutdown(true)
}); err != nil { }); err != nil {
return err return err
@ -272,20 +272,24 @@ func (s *APIServer) setupPprof() {
// Shutdown is a clean shutdown waiting on existing clients // Shutdown is a clean shutdown waiting on existing clients
func (s *APIServer) Shutdown(halt bool) error { func (s *APIServer) Shutdown(halt bool) error {
if s.idleTracker.Duration == UnlimitedServiceDuration && !halt { switch {
logrus.Debug("API service shutdown request ignored as Duration is UnlimitedService") case halt:
logrus.Debug("API service forced shutdown, ignoring timeout Duration")
case s.idleTracker.Duration == UnlimitedServiceDuration:
logrus.Debug("API service shutdown request ignored as timeout Duration is UnlimitedService")
return nil return nil
} }
shutdownOnce.Do(func() { shutdownOnce.Do(func() {
if logrus.IsLevelEnabled(logrus.DebugLevel) { logrus.Debugf("API service shutdown, %d/%d connection(s)",
_, file, line, _ := runtime.Caller(1) s.idleTracker.ActiveConnections(), s.idleTracker.TotalConnections())
logrus.Debugf("API service shutdown by %s:%d, %d/%d connection(s)",
file, line, s.idleTracker.ActiveConnections(), s.idleTracker.TotalConnections())
}
// Gracefully shutdown server(s), duration of wait same as idle window // Gracefully shutdown server(s), duration of wait same as idle window
ctx, cancel := context.WithTimeout(context.Background(), s.idleTracker.Duration) deadline := 1 * time.Second
if s.idleTracker.Duration > 0 {
deadline = s.idleTracker.Duration
}
ctx, cancel := context.WithTimeout(context.Background(), deadline)
go func() { go func() {
defer cancel() defer cancel()
@ -296,7 +300,6 @@ func (s *APIServer) Shutdown(halt bool) error {
}() }()
<-ctx.Done() <-ctx.Done()
}) })
return nil return nil
} }

View File

@ -65,7 +65,7 @@ var _ = Describe("podman system service", func() {
pprofPort := randomPort() pprofPort := randomPort()
session := podmanTest.Podman([]string{ session := podmanTest.Podman([]string{
"system", "service", "--log-level=info", "--time=0", "system", "service", "--log-level=debug", "--time=0",
"--pprof-address=localhost:" + pprofPort, address.String(), "--pprof-address=localhost:" + pprofPort, address.String(),
}) })
defer session.Kill() defer session.Kill()
@ -91,7 +91,7 @@ var _ = Describe("podman system service", func() {
Expect(body).ShouldNot(BeEmpty()) Expect(body).ShouldNot(BeEmpty())
session.Interrupt().Wait(2 * time.Second) session.Interrupt().Wait(2 * time.Second)
Eventually(session, 2).Should(Exit(1)) Eventually(session).Should(Exit(1))
}) })
It("are not available", func() { It("are not available", func() {
@ -103,7 +103,7 @@ var _ = Describe("podman system service", func() {
} }
session := podmanTest.Podman([]string{ session := podmanTest.Podman([]string{
"system", "service", "--log-level=info", "--time=0", address.String(), "system", "service", "--log-level=debug", "--time=0", address.String(),
}) })
defer session.Kill() defer session.Kill()
@ -113,7 +113,7 @@ var _ = Describe("podman system service", func() {
Expect(session.Err.Contents()).ShouldNot(ContainSubstring(magicComment)) Expect(session.Err.Contents()).ShouldNot(ContainSubstring(magicComment))
session.Interrupt().Wait(2 * time.Second) session.Interrupt().Wait(2 * time.Second)
Eventually(session, 2).Should(Exit(1)) Eventually(session).Should(Exit(1))
}) })
}) })
}) })