github.com/haalcala/mattermost-server-change-repo@v0.0.0-20210713015153-16753fbeee5f/cmd/mattermost/commands/server.go (about) 1 // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. 2 // See LICENSE.txt for license information. 3 4 package commands 5 6 import ( 7 "bytes" 8 "net" 9 "os" 10 "os/signal" 11 "runtime/debug" 12 "runtime/pprof" 13 "syscall" 14 15 "github.com/pkg/errors" 16 "github.com/spf13/cobra" 17 18 "github.com/mattermost/mattermost-server/v5/api4" 19 "github.com/mattermost/mattermost-server/v5/app" 20 "github.com/mattermost/mattermost-server/v5/config" 21 "github.com/mattermost/mattermost-server/v5/manualtesting" 22 "github.com/mattermost/mattermost-server/v5/mlog" 23 "github.com/mattermost/mattermost-server/v5/utils" 24 "github.com/mattermost/mattermost-server/v5/web" 25 "github.com/mattermost/mattermost-server/v5/wsapi" 26 ) 27 28 var serverCmd = &cobra.Command{ 29 Use: "server", 30 Short: "Run the Mattermost server", 31 RunE: serverCmdF, 32 SilenceUsage: true, 33 } 34 35 func init() { 36 RootCmd.AddCommand(serverCmd) 37 RootCmd.RunE = serverCmdF 38 } 39 40 func serverCmdF(command *cobra.Command, args []string) error { 41 disableConfigWatch, _ := command.Flags().GetBool("disableconfigwatch") 42 usedPlatform, _ := command.Flags().GetBool("platform") 43 44 interruptChan := make(chan os.Signal, 1) 45 46 if err := utils.TranslationsPreInit(); err != nil { 47 return errors.Wrap(err, "unable to load Mattermost translation files") 48 } 49 50 customDefaults, err := loadCustomDefaults() 51 if err != nil { 52 mlog.Warn("Error loading custom configuration defaults: " + err.Error()) 53 } 54 55 configStore, err := config.NewStore(getConfigDSN(command, config.GetEnvironment()), !disableConfigWatch, false, customDefaults) 56 if err != nil { 57 return errors.Wrap(err, "failed to load configuration") 58 } 59 defer configStore.Close() 60 61 return runServer(configStore, usedPlatform, interruptChan) 62 } 63 64 func runServer(configStore *config.Store, usedPlatform bool, interruptChan chan os.Signal) error { 65 // Setting the highest traceback level from the code. 66 // This is done to print goroutines from all threads (see golang.org/issue/13161) 67 // and also preserve a crash dump for later investigation. 68 debug.SetTraceback("crash") 69 70 options := []app.Option{ 71 app.ConfigStore(configStore), 72 app.RunJobs, 73 app.JoinCluster, 74 app.StartSearchEngine, 75 app.StartMetrics, 76 } 77 server, err := app.NewServer(options...) 78 if err != nil { 79 mlog.Critical(err.Error()) 80 return err 81 } 82 defer server.Shutdown() 83 // We add this after shutdown so that it can be called 84 // before server shutdown happens as it can close 85 // the advanced logger and prevent the mlog call from working properly. 86 defer func() { 87 // A panic pass-through layer which just logs it 88 // and sends it upwards. 89 if x := recover(); x != nil { 90 var buf bytes.Buffer 91 pprof.Lookup("goroutine").WriteTo(&buf, 2) 92 mlog.Critical("A panic occurred", 93 mlog.Any("error", x), 94 mlog.String("stack", buf.String())) 95 panic(x) 96 } 97 }() 98 99 if usedPlatform { 100 mlog.Warn("The platform binary has been deprecated, please switch to using the mattermost binary.") 101 } 102 103 api := api4.Init(server, server.AppOptions, server.Router) 104 wsapi.Init(server) 105 web.New(server, server.AppOptions, server.Router) 106 api4.InitLocal(server, server.AppOptions, server.LocalRouter) 107 108 serverErr := server.Start() 109 if serverErr != nil { 110 mlog.Critical(serverErr.Error()) 111 return serverErr 112 } 113 114 // If we allow testing then listen for manual testing URL hits 115 if *server.Config().ServiceSettings.EnableTesting { 116 manualtesting.Init(api) 117 } 118 119 notifyReady() 120 121 // wait for kill signal before attempting to gracefully shutdown 122 // the running service 123 signal.Notify(interruptChan, syscall.SIGINT, syscall.SIGTERM) 124 <-interruptChan 125 126 return nil 127 } 128 129 func notifyReady() { 130 // If the environment vars provide a systemd notification socket, 131 // notify systemd that the server is ready. 132 systemdSocket := os.Getenv("NOTIFY_SOCKET") 133 if systemdSocket != "" { 134 mlog.Info("Sending systemd READY notification.") 135 136 err := sendSystemdReadyNotification(systemdSocket) 137 if err != nil { 138 mlog.Error(err.Error()) 139 } 140 } 141 } 142 143 func sendSystemdReadyNotification(socketPath string) error { 144 msg := "READY=1" 145 addr := &net.UnixAddr{ 146 Name: socketPath, 147 Net: "unixgram", 148 } 149 conn, err := net.DialUnix(addr.Net, nil, addr) 150 if err != nil { 151 return err 152 } 153 defer conn.Close() 154 _, err = conn.Write([]byte(msg)) 155 return err 156 }