exitProcess exits the process as gracefully as possible, but it always exits, even if there are errors doing so. It stops all apps, cleans up external locks, removes any PID file, and shuts down admin endpoint(s) in a goroutine. Errors are logged along the way, and an appropriate exit code is emitte
(ctx context.Context, logger *zap.Logger)
| 758 | // Errors are logged along the way, and an appropriate exit |
| 759 | // code is emitted. |
| 760 | func exitProcess(ctx context.Context, logger *zap.Logger) { |
| 761 | // let the rest of the program know we're quitting; only do it once |
| 762 | if !exiting.CompareAndSwap(false, true) { |
| 763 | return |
| 764 | } |
| 765 | |
| 766 | // give the OS or service/process manager our 2 weeks' notice: we quit |
| 767 | if err := notify.Stopping(); err != nil { |
| 768 | Log().Error("unable to notify service manager of stopping state", zap.Error(err)) |
| 769 | } |
| 770 | |
| 771 | if logger == nil { |
| 772 | logger = Log() |
| 773 | } |
| 774 | logger.Warn("exiting; byeee!! 👋") |
| 775 | |
| 776 | exitCode := ExitCodeSuccess |
| 777 | lastContext := ActiveContext() |
| 778 | |
| 779 | // stop all apps |
| 780 | if err := Stop(); err != nil { |
| 781 | logger.Error("failed to stop apps", zap.Error(err)) |
| 782 | exitCode = ExitCodeFailedQuit |
| 783 | } |
| 784 | |
| 785 | // clean up certmagic locks |
| 786 | certmagic.CleanUpOwnLocks(ctx, logger) |
| 787 | |
| 788 | // remove pidfile |
| 789 | if pidfile != "" { |
| 790 | err := os.Remove(pidfile) |
| 791 | if err != nil { |
| 792 | logger.Error("cleaning up PID file:", |
| 793 | zap.String("pidfile", pidfile), |
| 794 | zap.Error(err)) |
| 795 | exitCode = ExitCodeFailedQuit |
| 796 | } |
| 797 | } |
| 798 | |
| 799 | // execute any process-exit callbacks |
| 800 | for _, exitFunc := range lastContext.exitFuncs { |
| 801 | exitFunc(ctx) |
| 802 | } |
| 803 | exitFuncsMu.Lock() |
| 804 | for _, exitFunc := range exitFuncs { |
| 805 | exitFunc(ctx) |
| 806 | } |
| 807 | exitFuncsMu.Unlock() |
| 808 | |
| 809 | // shut down admin endpoint(s) in goroutines so that |
| 810 | // if this function was called from an admin handler, |
| 811 | // it has a chance to return gracefully |
| 812 | // use goroutine so that we can finish responding to API request |
| 813 | go func() { |
| 814 | defer func() { |
| 815 | logger = logger.With(zap.Int("exit_code", exitCode)) |
| 816 | if exitCode == ExitCodeSuccess { |
| 817 | logger.Info("shutdown complete") |
no test coverage detected