package main import ( "context" "encoding/json" "log" "net/http" _ "net/http/pprof" "os" "os/signal" "syscall" "time" "geeks-accelerator/oss/saas-starter-kit/example-project/cmd/sidecar/tracer/handlers" "github.com/kelseyhightower/envconfig" ) func main() { // ========================================================================= // Logging log := log.New(os.Stdout, "TRACER : ", log.LstdFlags|log.Lmicroseconds|log.Lshortfile) defer log.Println("main : Completed") // ========================================================================= // Configuration var cfg struct { Web struct { APIHost string `default:"0.0.0.0:3002" envconfig:"API_HOST"` DebugHost string `default:"0.0.0.0:4002" envconfig:"DEBUG_HOST"` ReadTimeout time.Duration `default:"5s" envconfig:"READ_TIMEOUT"` WriteTimeout time.Duration `default:"5s" envconfig:"WRITE_TIMEOUT"` ShutdownTimeout time.Duration `default:"5s" envconfig:"SHUTDOWN_TIMEOUT"` } Zipkin struct { Host string `default:"http://zipkin:9411/api/v2/spans" envconfig:"HOST"` } } if err := envconfig.Process("TRACER", &cfg); err != nil { log.Fatalf("main : Parsing Config : %v", err) } cfgJSON, err := json.MarshalIndent(cfg, "", " ") if err != nil { log.Fatalf("main : Marshalling Config to JSON : %v", err) } log.Printf("config : %v\n", string(cfgJSON)) // ========================================================================= // Start Debug Service. Not concerned with shutting this down when the // application is being shutdown. // // /debug/pprof - Added to the default mux by the net/http/pprof package. go func() { log.Printf("main : Debug Listening %s", cfg.Web.DebugHost) log.Printf("main : Debug Listener closed : %v", http.ListenAndServe(cfg.Web.DebugHost, http.DefaultServeMux)) }() // ========================================================================= // Start API Service // Make a channel to listen for an interrupt or terminate signal from the OS. // Use a buffered channel because the signal package requires it. shutdown := make(chan os.Signal, 1) signal.Notify(shutdown, os.Interrupt, syscall.SIGTERM) api := http.Server{ Addr: cfg.Web.APIHost, Handler: handlers.API(shutdown, log, cfg.Zipkin.Host, cfg.Web.APIHost), ReadTimeout: cfg.Web.ReadTimeout, WriteTimeout: cfg.Web.WriteTimeout, MaxHeaderBytes: 1 << 20, } // Make a channel to listen for errors coming from the listener. Use a // buffered channel so the goroutine can exit if we don't collect this error. serverErrors := make(chan error, 1) // Start the service listening for requests. go func() { log.Printf("main : API Listening %s", cfg.Web.APIHost) serverErrors <- api.ListenAndServe() }() // ========================================================================= // Shutdown // Blocking main and waiting for shutdown. select { case err := <-serverErrors: log.Fatalf("main : Error starting server: %v", err) case sig := <-shutdown: log.Printf("main : %v : Start shutdown..", sig) // Create context for Shutdown call. ctx, cancel := context.WithTimeout(context.Background(), cfg.Web.ShutdownTimeout) defer cancel() // Asking listener to shutdown and load shed. err := api.Shutdown(ctx) if err != nil { log.Printf("main : Graceful shutdown did not complete in %v : %v", cfg.Web.ShutdownTimeout, err) err = api.Close() } // Log the status of this shutdown. switch { case sig == syscall.SIGSTOP: log.Fatal("main : Integrity issue caused shutdown") case err != nil: log.Fatalf("main : Could not stop server gracefully : %v", err) } } }