@@ -715,6 +715,7 @@ func exitProcess(ctx context.Context, logger *zap.Logger) {
715
715
logger .Warn ("exiting; byeee!! 👋" )
716
716
717
717
exitCode := ExitCodeSuccess
718
+ lastContext := ActiveContext ()
718
719
719
720
// stop all apps
720
721
if err := Stop (); err != nil {
@@ -736,6 +737,16 @@ func exitProcess(ctx context.Context, logger *zap.Logger) {
736
737
}
737
738
}
738
739
740
+ // execute any process-exit callbacks
741
+ for _ , exitFunc := range lastContext .exitFuncs {
742
+ exitFunc (ctx )
743
+ }
744
+ exitFuncsMu .Lock ()
745
+ for _ , exitFunc := range exitFuncs {
746
+ exitFunc (ctx )
747
+ }
748
+ exitFuncsMu .Unlock ()
749
+
739
750
// shut down admin endpoint(s) in goroutines so that
740
751
// if this function was called from an admin handler,
741
752
// it has a chance to return gracefully
@@ -774,6 +785,23 @@ var exiting = new(int32) // accessed atomically
774
785
// EXPERIMENTAL API: subject to change or removal.
775
786
func Exiting () bool { return atomic .LoadInt32 (exiting ) == 1 }
776
787
788
+ // OnExit registers a callback to invoke during process exit.
789
+ // This registration is PROCESS-GLOBAL, meaning that each
790
+ // function should only be registered once forever, NOT once
791
+ // per config load (etc).
792
+ //
793
+ // EXPERIMENTAL API: subject to change or removal.
794
+ func OnExit (f func (context.Context )) {
795
+ exitFuncsMu .Lock ()
796
+ exitFuncs = append (exitFuncs , f )
797
+ exitFuncsMu .Unlock ()
798
+ }
799
+
800
+ var (
801
+ exitFuncs []func (context.Context )
802
+ exitFuncsMu sync.Mutex
803
+ )
804
+
777
805
// Duration can be an integer or a string. An integer is
778
806
// interpreted as nanoseconds. If a string, it is a Go
779
807
// time.Duration value such as `300ms`, `1.5h`, or `2h45m`;
0 commit comments