drone/cmd/gitrpcserver/main.go

161 lines
4.2 KiB
Go

// Copyright 2023 Harness, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
import (
"context"
"fmt"
"os"
"os/signal"
"syscall"
"time"
"github.com/harness/gitness/profiler"
"github.com/harness/gitness/version"
"github.com/joho/godotenv"
"github.com/mattn/go-isatty"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
"golang.org/x/sync/errgroup"
"gopkg.in/alecthomas/kingpin.v2"
)
const (
application = "gitrpcserver"
description = "GitRPC is a GRPC server that exposes git via RPC."
)
func main() {
// define new kingpin application with global entry point
app := kingpin.New(application, description)
app.Version(version.Version.String())
var envFile string
app.Action(func(*kingpin.ParseContext) error { return run(envFile) })
app.Arg("envfile", "load the environment variable file").
Default("").
StringVar(&envFile)
// trigger execution
kingpin.MustParse(app.Parse(os.Args[1:]))
}
func run(envFile string) error {
// Create context that listens for the interrupt signal from the OS.
ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
defer stop()
if envFile != "" {
if err := godotenv.Load(envFile); err != nil {
return fmt.Errorf("failed to load environment file: %w", err)
}
}
config, err := loadConfig()
if err != nil {
return fmt.Errorf("failed to load config: %w", err)
}
// setup logger and inject into context
setupLogger(config)
log := log.Logger.With().Logger()
ctx = log.WithContext(ctx)
setupProfiler(config)
system, err := initSystem()
if err != nil {
return fmt.Errorf("failed to init gitrpc server: %w", err)
}
// gCtx is canceled if any of the following occurs:
// - any go routine launched with g encounters an error
// - ctx is canceled
g, gCtx := errgroup.WithContext(ctx)
// start grpc server
g.Go(system.grpcServer.Start)
log.Info().Msg("grpc server started")
gHTTP, shutdownHTTP := system.httpServer.ListenAndServe()
g.Go(gHTTP.Wait)
log.Info().Msgf("http server started")
// 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(), config.GracefulShutdownTime)
defer cancel()
if rpcErr := system.grpcServer.Stop(); rpcErr != nil {
log.Err(rpcErr).Msg("failed to shutdown grpc server gracefully")
}
if sErr := shutdownHTTP(shutdownCtx); sErr != nil {
log.Err(sErr).Msg("failed to shutdown http 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 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",
},
)
}
}
func setupProfiler(config Config) {
profilerType, parsed := profiler.ParseType(config.Profiler.Type)
if !parsed {
log.Info().Msgf("No valid profiler so skipping profiling ['%s']", config.Profiler.Type)
return
}
gitrpcProfiler, _ := profiler.New(profilerType)
gitrpcProfiler.StartProfiling(config.Profiler.ServiceName, version.Version.String())
}