diff --git a/server/channels/app/channels.go b/server/channels/app/channels.go index b6ed4be31e..cc10f3643b 100644 --- a/server/channels/app/channels.go +++ b/server/channels/app/channels.go @@ -4,9 +4,12 @@ package app import ( + "os" + "os/signal" "runtime" "strings" "sync" + "syscall" "github.com/pkg/errors" @@ -77,6 +80,7 @@ type Channels struct { postReminderMut sync.Mutex postReminderTask *model.ScheduledTask + interruptQuitChan chan struct{} scheduledPostMut sync.Mutex scheduledPostTask *model.ScheduledTask loginAttemptsMut sync.Mutex @@ -84,12 +88,13 @@ type Channels struct { func NewChannels(s *Server) (*Channels, error) { ch := &Channels{ - srv: s, - imageProxy: imageproxy.MakeImageProxy(s.platform, s.httpService, s.Log()), - uploadLockMap: map[string]bool{}, - filestore: s.FileBackend(), - exportFilestore: s.ExportFileBackend(), - cfgSvc: s.Platform(), + srv: s, + imageProxy: imageproxy.MakeImageProxy(s.platform, s.httpService, s.Log()), + uploadLockMap: map[string]bool{}, + filestore: s.FileBackend(), + exportFilestore: s.ExportFileBackend(), + cfgSvc: s.Platform(), + interruptQuitChan: make(chan struct{}), } // We are passing a partially filled Channels struct so that the enterprise @@ -159,6 +164,20 @@ func (ch *Channels) Start() error { ctx := request.EmptyContext(ch.srv.Log()) ch.initPlugins(ctx, *ch.cfgSvc.Config().PluginSettings.Directory, *ch.cfgSvc.Config().PluginSettings.ClientDirectory) + interruptChan := make(chan os.Signal, 1) + signal.Notify(interruptChan, syscall.SIGINT, syscall.SIGTERM) + go func() { + select { + case <-interruptChan: + if err := ch.Stop(); err != nil { + ch.srv.Log().Warn("Error stopping channels", mlog.Err(err)) + } + os.Exit(1) + case <-ch.interruptQuitChan: + return + } + }() + ch.AddConfigListener(func(prevCfg, cfg *model.Config) { // We compute the difference between configs // to ensure we don't re-init plugins unnecessarily. @@ -208,6 +227,8 @@ func (ch *Channels) Stop() error { } ch.dndTaskMut.Unlock() + close(ch.interruptQuitChan) + return nil } diff --git a/server/cmd/mattermost/commands/server.go b/server/cmd/mattermost/commands/server.go index 642bd95b78..76d33bfaf3 100644 --- a/server/cmd/mattermost/commands/server.go +++ b/server/cmd/mattermost/commands/server.go @@ -109,6 +109,10 @@ func runServer(configStore *config.Store, interruptChan chan os.Signal) error { notifyReady() + // Wiping off any signal handlers set before. + // This may come from intermediary signal handlers requiring to clean + // up resources before server.Start can finish. + signal.Reset(syscall.SIGINT, syscall.SIGTERM) // wait for kill signal before attempting to gracefully shutdown // the running service signal.Notify(interruptChan, syscall.SIGINT, syscall.SIGTERM) diff --git a/server/public/plugin/environment.go b/server/public/plugin/environment.go index 289b55ea83..b8f46e60f0 100644 --- a/server/public/plugin/environment.go +++ b/server/public/plugin/environment.go @@ -483,7 +483,7 @@ func (env *Environment) Shutdown() { env.TogglePluginHealthCheckJob(false) var wg sync.WaitGroup - env.registeredPlugins.Range(func(key, value any) bool { + env.registeredPlugins.Range(func(_, value any) bool { rp := value.(registeredPlugin) if rp.supervisor == nil || !env.IsActive(rp.BundleInfo.Manifest.Id) {