drone/cli/server/server.go
Johannes Batzill c8cee4d250 [Misc] Preparation for Container Deployment (#67)
This change is fixing our docker file which is used to build our harness code image used for PR deployments.
Furthermore, the change contains some logging improvements that were added along the way of setting up the PR environment.
2022-11-09 23:03:40 -08:00

159 lines
4.0 KiB
Go

// Copyright 2022 Harness Inc. All rights reserved.
// Use of this source code is governed by the Polyform Free Trial License
// that can be found in the LICENSE.md file for this repository.
package server
import (
"context"
"fmt"
"os"
"os/signal"
"syscall"
"time"
"github.com/harness/gitness/types"
"github.com/harness/gitness/version"
"golang.org/x/sync/errgroup"
"github.com/joho/godotenv"
"github.com/mattn/go-isatty"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
"gopkg.in/alecthomas/kingpin.v2"
)
const (
// GraceFullShutdownTime defines the max time we wait when shutting down a server.
// 5min should be enough for most git clones to complete.
GraceFullShutdownTime = 300 * time.Second
)
type command struct {
envfile string
}
func (c *command) run(*kingpin.ParseContext) error {
// Create context that listens for the interrupt signal from the OS.
ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
defer stop()
// load environment variables from file.
// no error handling needed when file is not present
_ = godotenv.Load(c.envfile)
// create the system configuration store by loading
// data from the environment.
config, err := load()
if err != nil {
return fmt.Errorf("encountered an error while loading configuration: %w", err)
}
// configure the log level
setupLogger(config)
// add logger to context
log := log.Logger.With().Logger()
ctx = log.WithContext(ctx)
// initialize system
system, err := initSystem(ctx, config)
if err != nil {
return fmt.Errorf("encountered an error while wiring the system: %w", err)
}
// bootstrap the system
err = system.bootstrap(ctx)
if err != nil {
return fmt.Errorf("encountered an error while bootstrapping the system: %w", err)
}
// collects all go routines - gCTX cancels if any go routine encounters an error
g, gCtx := errgroup.WithContext(ctx)
// start server
gHTTP, shutdownHTTP := system.server.ListenAndServe()
g.Go(gHTTP.Wait)
log.Info().
Str("port", config.Server.HTTP.Bind).
Str("revision", version.GitCommit).
Str("repository", version.GitRepository).
Stringer("version", version.Version).
Msg("server started")
// start the purge routine.
g.Go(func() error {
system.nightly.Run(gCtx)
return nil
})
log.Info().Msg("nightly subroutine started")
// start grpc server
g.Go(system.gitRPCServer.Start)
// wait until the error group context is done
<-gCtx.Done()
// restore default behavior on the interrupt signal and notify user of shutdown.
stop()
log.Info().Msg("shutting down gracefully (press Ctrl+C again to force)")
// shutdown servers gracefully
shutdownCtx, cancel := context.WithTimeout(context.Background(), GraceFullShutdownTime)
defer cancel()
if sErr := shutdownHTTP(shutdownCtx); sErr != nil {
log.Err(sErr).Msg("failed to shutdown http server gracefully")
}
if rpcErr := system.gitRPCServer.Stop(); rpcErr != nil {
log.Err(rpcErr).Msg("failed to shutdown grpc server gracefully")
}
log.Info().Msg("wait for subroutines to complete")
err = g.Wait()
return err
}
// helper function configures the global logger from
// the loaded configuration.
func setupLogger(config *types.Config) {
// configure the log level
switch {
case config.Trace:
zerolog.SetGlobalLevel(zerolog.TraceLevel)
case config.Debug:
zerolog.SetGlobalLevel(zerolog.DebugLevel)
default:
zerolog.SetGlobalLevel(zerolog.InfoLevel)
}
// configure time format (ignored if running in terminal)
zerolog.TimeFieldFormat = time.RFC3339Nano
// if the terminal is a tty we should output the
// logs in pretty format
if isatty.IsTerminal(os.Stdout.Fd()) {
log.Logger = log.Output(
zerolog.ConsoleWriter{
Out: os.Stderr,
NoColor: false,
TimeFormat: "15:04:05.999",
},
)
}
}
// Register the server command.
func Register(app *kingpin.Application) {
c := new(command)
cmd := app.Command("server", "starts the server").
Action(c.run)
cmd.Arg("envfile", "load the environment variable file").
Default("").
StringVar(&c.envfile)
}