1
0
Fork 0
api_skeleton/main.go

150 lines
3.9 KiB
Go

package main
import (
"os"
"os/signal"
"runtime"
"syscall"
"time"
"amuz.es/gogs/infra/api_skeleton/subsys/http"
"amuz.es/gogs/infra/api_skeleton/subsys/periodic"
"amuz.es/gogs/infra/api_skeleton/util"
"gopkg.in/alecthomas/kingpin.v2"
"sync"
"context"
)
var (
app = kingpin.New(util.Config.Name(), "graceful API server").Author("tom.cat")
verbose = app.Flag("verbose", "Enable verbose mode.").Short('v').Bool()
logDir = app.Flag("log-dir", "logstore directory.").Short('L').String()
configFile = app.Flag("config-file", "config file path").Default("settings.yml").HintOptions("FILENAME").Short('C').String()
logger = util.NewLogger("main")
)
func systemStart(ctx context.Context, errorSignal chan error, waiter *sync.WaitGroup) {
defer func() {
if err := recover(); err != nil {
errorSignal <- err.(error)
}
}()
start := time.Now()
app.Version(util.Config.Version())
if _, err := app.Parse(os.Args[1:]); err != nil {
panic(err)
}
setMaxProcs()
if err := util.LoadConfig(*configFile); err != nil {
panic(err)
}
util.InitLogger(*verbose, *logDir, &util.Config.Logging.Application)
showBanner(util.Config.Phase, util.Config.Version(), util.Config.BuildDate())
// init subsystem
//db.InitDB(&util.Config.Db)
//redis.InitRedis(&util.Config.Redis)
//redis.AppTokenInitService(util.Config.Phase, util.Config.AppToken.Expires, util.Config.AppToken.RefreshExpires)
//redis.UploadFileInitService(util.Config.Phase, util.Config.AppToken.UploadRetryExpires)
periodic.Start(errorSignal, ctx, waiter)
http.Start(util.Config.Bind, &util.Config.Logging.Access, errorSignal, ctx, waiter)
logger.Info("bootstrapped application ", time.Since(start))
util.NotifyDaemon(util.DaemonStarted)
}
func systemReload() {
util.RotateLogger()
}
func systemTeardown(exitCode *int, waiter *sync.WaitGroup) {
logger.Info("closing application")
util.NotifyDaemon(util.DaemonStopping)
waiter.Wait()
//redis.CloseRedis()
logger.Info("bye")
os.Exit(*exitCode)
}
func main() {
var (
exitCode = 0
ctx, canceled = context.WithCancel(context.Background())
waiter = &sync.WaitGroup{}
exitSignal = make(chan os.Signal, 1)
errorSignal = make(chan error, 10)
)
systemStart(ctx, errorSignal, waiter)
defer systemTeardown(&exitCode, waiter)
signal.Notify(exitSignal, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP)
for {
select {
case <-ctx.Done():
logger.Info("Service request to close this application")
return
case sysSignal := <-exitSignal:
switch sysSignal {
case syscall.SIGHUP:
systemReload()
default:
canceled()
logger.Info("SYSCALL! ", sysSignal.String())
return
}
case err := <-errorSignal:
canceled()
logger.Error("exception raised! ", err)
exitCode = -1
return
}
}
}
func setMaxProcs() {
// TODO(vmarmol): Consider limiting if we have a CPU mask in effect.
// Allow as many threads as we have cores unless the user specified a value.
var numProcs int
// if *maxProcs < 1 {
numProcs = runtime.NumCPU()
// } else {
// numProcs = *maxProcs
// }
runtime.GOMAXPROCS(numProcs)
// Check if the setting was successful.
actualNumProcs := runtime.GOMAXPROCS(0)
if actualNumProcs != numProcs {
logger.Warn("Specified max procs of %v but using %v", numProcs, actualNumProcs)
}
}
func showBanner(phase string, version string, buildDate string) {
if util.LoggerIsStd() {
logger.Info(`
{
{ }
}_{ __{
.-{ } }-. ` + util.Config.Name() + `
( } { ) version: ` + version + `
` + "|`-.._____..-'| buildDate: " + buildDate + `
| ;--. phase: ` + phase + `
| (__ \
| | ) )
| |/ /
| / /
| ( /
\ y'
` + "`-.._____..-'")
} else {
logger.
WithField("version", version).
WithField("buildDate", buildDate).
WithField("phase", phase).
Info("##", util.Config.Name())
}
}