()
| 143 | } |
| 144 | |
| 145 | func start() { |
| 146 | handlerOptions := &slog.HandlerOptions{AddSource: true, Level: log.LogLevel, ReplaceAttr: log.Replace} |
| 147 | var handler slog.Handler |
| 148 | if flags.saas || flags.enableJSONLogging { |
| 149 | handler = slog.NewJSONHandler(os.Stdout, handlerOptions) |
| 150 | } else { |
| 151 | handler = slog.NewTextHandler(os.Stdout, handlerOptions) |
| 152 | } |
| 153 | slog.SetDefault(slog.New(log.NewContextHandler(handler))) |
| 154 | |
| 155 | var err error |
| 156 | |
| 157 | if flags.externalURL != "" { |
| 158 | flags.externalURL, err = common.NormalizeExternalURL(flags.externalURL) |
| 159 | if err != nil { |
| 160 | slog.Error("invalid --external-url", log.BBError(err)) |
| 161 | return |
| 162 | } |
| 163 | } |
| 164 | |
| 165 | if err := checkDataDir(); err != nil { |
| 166 | slog.Error(err.Error()) |
| 167 | return |
| 168 | } |
| 169 | |
| 170 | profile := activeProfile(flags.dataDir) |
| 171 | |
| 172 | fmt.Printf("Starting Bytebase %s(%s)...\n", profile.Version, profile.GitCommit) |
| 173 | |
| 174 | // The ideal bootstrap order is: |
| 175 | // 1. Connect to the metadb |
| 176 | // 2. Start echo server |
| 177 | // 3. Start various background runners |
| 178 | // |
| 179 | // Strangely, when the port is unavailable, echo server would return OK response for /healthz |
| 180 | // and then complain unable to bind port. Thus we cannot rely on checking /healthz. As a |
| 181 | // workaround, we check whether the port is available here. |
| 182 | if err := checkPort(flags.port); err != nil { |
| 183 | slog.Error(fmt.Sprintf("server port %d is not available", flags.port), log.BBError(err)) |
| 184 | return |
| 185 | } |
| 186 | if profile.UseEmbedDB() { |
| 187 | if err := checkPort(profile.DatastorePort); err != nil { |
| 188 | slog.Error(fmt.Sprintf("database port %d is not available", profile.DatastorePort), log.BBError(err)) |
| 189 | return |
| 190 | } |
| 191 | } |
| 192 | |
| 193 | var s *server.Server |
| 194 | // Setup signal handlers. |
| 195 | ctx, cancel := context.WithCancel(context.Background()) |
| 196 | c := make(chan os.Signal, 1) |
| 197 | // Trigger graceful shutdown on SIGINT or SIGTERM. |
| 198 | // The default signal sent by the `kill` command is SIGTERM, |
| 199 | // which is taken as the graceful shutdown signal for many systems, eg., Kubernetes, Gunicorn. |
| 200 | signal.Notify(c, os.Interrupt, syscall.SIGTERM) |
| 201 | go func() { |
| 202 | sig := <-c |
no test coverage detected