Created
October 15, 2019 09:08
-
-
Save a-hilaly/834e71146144a2f8b580e84dcf6e82b5 to your computer and use it in GitHub Desktop.
grpc + json proxy
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package start | |
import ( | |
"context" | |
"fmt" | |
"net" | |
"net/http" | |
"os" | |
"os/signal" | |
"time" | |
"github.com/go-xorm/core" | |
"github.com/sirupsen/logrus" | |
"github.com/spf13/cobra" | |
"gitlab.com/supbank/api/pkg/auth" | |
"gitlab.com/supbank/api/pkg/bc" | |
"gitlab.com/supbank/api/pkg/cmd" | |
configpb "gitlab.com/supbank/api/pkg/config" | |
"gitlab.com/supbank/api/pkg/drivers/postgres" | |
"gitlab.com/supbank/api/pkg/drivers/redis" | |
"gitlab.com/supbank/api/pkg/grpc" | |
grpcproxy "gitlab.com/supbank/api/pkg/grpc-proxy" | |
"gitlab.com/supbank/api/pkg/hc" | |
"gitlab.com/supbank/api/pkg/log" | |
"gitlab.com/supbank/api/pkg/store" | |
authv1 "gitlab.com/supbank/api/pkg/svc/v1/auth" | |
bcv1 "gitlab.com/supbank/api/pkg/svc/v1/bc" | |
hcv1 "gitlab.com/supbank/api/pkg/svc/v1/hc" | |
metav1 "gitlab.com/supbank/api/pkg/svc/v1/meta" | |
userv1 "gitlab.com/supbank/api/pkg/svc/v1/user" | |
walletv1 "gitlab.com/supbank/api/pkg/svc/v1/wallet" | |
"gitlab.com/supbank/api/pkg/valid" | |
) | |
var ( | |
config = configpb.NewEmpty() | |
) | |
func init() { | |
// startup options | |
Cmd.Flags().Int64VarP(&config.Options.GrpcPort, "grpc-port", "g", 11251, "grpc server port") | |
Cmd.Flags().Int64Var(&config.Options.GrpcProxyPort, "grpc-proxy-port", 11253, "grpx proxy server port") | |
Cmd.Flags().BoolVar(&config.Options.GrpcProxyOn, "grpc-proxy", true, "run grpc json proxy") | |
Cmd.Flags().BoolVar(&config.Options.SwaggerUI, "swagger-ui", true, "run swagger ui with grpc proxy") | |
// wait postgres | |
Cmd.Flags().BoolVar(&config.Options.WaitPostgres, "wait-postgres", true, "wait for postgres database before startup") | |
Cmd.Flags().Int64Var(&config.Options.WaitPostgresDelay, "wait-postgres-delay", 1000, "wait database delay (ms)") | |
Cmd.Flags().Int64Var(&config.Options.WaitPostgresMaxAttempts, "wait-postgres-max-attempts", 60, "wait database max attempt") | |
// wait redis | |
Cmd.Flags().BoolVar(&config.Options.WaitRedis, "wait-redis", true, "wait for redis before startup") | |
Cmd.Flags().Int64Var(&config.Options.WaitRedisDelay, "wait-redis-delay", 1000, "wait redis delay (ms)") | |
Cmd.Flags().Int64Var(&config.Options.WaitRedisMaxAttempts, "wait-redis-max-attempts", 60, "wait redis max attempt") | |
// database utility | |
Cmd.Flags().BoolVarP(&config.Options.CreateTables, "database-create-tables", "d", true, "create database tables") | |
Cmd.Flags().BoolVar(&config.Options.CreateTokens, "auth-create-tokens", true, "create database tables") | |
Cmd.Flags().BoolVar(&config.Options.PopulateDb, "database-prepend", true, "populate database with data") | |
Cmd.Flags().BoolVar(&config.Options.Production, "production", false, "production logging") | |
Cmd.Flags().StringVar(&config.Options.PrependDataPath, "data-prepend-file", "/etc/api/data.yaml", "prepend data from file") | |
// logging and runtime options | |
Cmd.Flags().Int64VarP(&config.Options.LoggingLevel, "logging", "v", 6, "logging level") | |
Cmd.Flags().Int64Var(&config.Options.CpuCount, "cpu-count", 0, "cpu usage count") | |
Cmd.Flags().Int64Var(&config.Options.ShutdownDelay, "shutdown-delay", 10000, "shutdown delay (ms)") | |
// postgres config | |
Cmd.Flags().StringVarP(&config.Postgres.Name, "postgres-database", "p", "supbank", "database name") | |
Cmd.Flags().StringVar(&config.Postgres.Hostname, "postgres-host", "postgres", "postgres hostname") | |
Cmd.Flags().StringVar(&config.Postgres.Protocol, "postgres-protocol", "tcp", "postgres protocol") | |
Cmd.Flags().StringVar(&config.Postgres.User, "postgres-user", "supbank", "postgres user") | |
Cmd.Flags().StringVar(&config.Postgres.Password, "postgres-password", "supbank", "postgres password") | |
Cmd.Flags().Int64Var(&config.Postgres.Port, "postgres-port", 5432, "postgres port") | |
Cmd.Flags().Int64Var(&config.Postgres.MaxOpenConnections, "postgres-max-open-connections", 10, "max open connections") | |
Cmd.Flags().Int64Var(&config.Postgres.MaxIdleConnections, "postgres-max-idle-connections", 10, "max idle connections") | |
Cmd.Flags().Int64Var(&config.Postgres.MaxConnectionLifetime, "postgres-max-connection-liftime", 2500, "max connection lifetime") | |
// redis config | |
Cmd.Flags().Uint32VarP(&config.Redis.Database, "redis-database", "r", 0, "database name") | |
Cmd.Flags().StringVar(&config.Redis.Hostname, "redis-host", "redis", "hostname") | |
Cmd.Flags().StringVar(&config.Redis.Protocol, "redis-protocol", "tcp", "redis protocol") | |
Cmd.Flags().StringVar(&config.Redis.Password, "redis-password", "", "redis password") | |
Cmd.Flags().Int64Var(&config.Redis.Port, "redis-port", 6379, "redis port") | |
Cmd.Flags().Int64Var(&config.Redis.MaxRetries, "redis-max-retries", 0, "redis default max retries") | |
Cmd.Flags().Int64Var(&config.Redis.DialTimeout, "redis-dial-timeout", 5000, "redis dial max time out (minutes)") | |
// auth service | |
Cmd.Flags().BoolVarP(&config.Options.AuthServiceOn, "auth", "A", true, "activate auth service") | |
Cmd.Flags().StringVar(&config.AuthService.GenAlgo, "auth-gen-algo", "sha256", "token gen algo") | |
Cmd.Flags().StringVar(&config.AuthService.Secret, "auth-secret", "****", "token key prefix in redis") | |
Cmd.Flags().StringVar(&config.AuthService.HashAlgo, "auth-hash-salt", "****", "token key prefix in redis") | |
Cmd.Flags().StringVar(&config.AuthService.HashAlgo, "auth-hash-algo", "sha256", "token key prefix in redis") | |
Cmd.Flags().Int64Var(&config.AuthService.TokenLifetime, "auth-token-lifetime", 172800, "session lifetime (minutes)") | |
Cmd.Flags().StringVar(&config.AuthService.TokenKeyPrefix, "auth-token-key-prefix", "/auth/token/", "token key prefix in redis") | |
Cmd.Flags().StringArrayVar(&config.AuthService.DebugTokens, "auth-debug", []string{"DEBUG", "SUPBANK"}, "token key prefix in redis") | |
// meta service | |
Cmd.Flags().BoolVarP(&config.Options.MetaServiceOn, "meta", "M", true, "activate meta service") | |
Cmd.Flags().StringVar(&config.MetaService.Hostname, "meta-hostname", os.Getenv("HOSTNAME"), "hostname information") | |
Cmd.Flags().StringVar(&config.MetaService.Namespace, "meta-namespace", os.Getenv("NAMESPACE"), "redis namespace inforamtion") | |
Cmd.Flags().StringVar(&config.MetaService.Kind, "meta-kind", os.Getenv("KIND"), "kind information") | |
Cmd.Flags().StringVar(&config.MetaService.Role, "meta-role", os.Getenv("ROLE"), "role information") | |
// user service | |
Cmd.Flags().BoolVarP(&config.Options.UserServiceOn, "user", "U", true, "activate user service") | |
Cmd.Flags().StringVar(&config.UserService.HashAlgo, "user-hash-algo", "sha256", "hash to use for passwords at signup") | |
// health check service | |
Cmd.Flags().BoolVarP(&config.Options.UserServiceOn, "hc", "H", true, "activate health check service") | |
// blockchain service | |
Cmd.Flags().StringVar(&config.BlockchainService.Node, "blockchain-node", "node-0", "node name") | |
Cmd.Flags().StringVar(&config.BlockchainService.Addr, "blockchain-addr", "127.0.0.1:19000", "node address") | |
} | |
var Cmd = &cobra.Command{ | |
Use: "start", | |
Short: "start grpc & proxy server and control startup strategy", | |
Run: startServer, | |
} | |
func startServer(*cobra.Command, []string) { | |
// init logging entry | |
logger := logrus.New() | |
logger.SetLevel(logrus.Level(config.Options.LoggingLevel)) | |
if config.Options.Production { | |
logger.SetFormatter(&logrus.JSONFormatter{}) | |
} | |
logrusEntry := logrus.NewEntry(logger) | |
// set package met logger | |
log.Set(logrusEntry) | |
// postgres client engine | |
postgresEngine, err := postgres.New(config.Postgres) | |
if err != nil { | |
log.Fatal("init database engine: %v", err) | |
} | |
// new postgres store | |
dbStore, _ := store.New(postgresEngine) | |
dbStore.GetEngine().SetLogLevel(core.LOG_OFF) | |
// wait for database ping response | |
if config.Options.WaitPostgres { | |
err := cmd.WaitPostgres(dbStore.GetEngine(), config) | |
if err != nil { | |
log.Fatal("postgres host isn't up: %v", err) | |
} | |
} | |
// initialize database | |
// create tables and populate with fake data | |
if config.Options.CreateTables { | |
// create tables | |
err := dbStore.Sync() | |
if err != nil { | |
log.Fatal("create tables: %v", err) | |
} | |
} | |
if config.Options.PopulateDb { | |
err := cmd.PopulateDatabase(dbStore, config) | |
if err != nil { | |
log.Fatal("populate db: %v", err) | |
} | |
} | |
// Initiliazing cache | |
redisClient, err := redis.New(config.Redis) | |
if err != nil { | |
log.Info("init cache client error: %v", err) | |
} | |
// wait for database ping response | |
if config.Options.WaitRedis { | |
err := cmd.WaitRedis(redisClient, config) | |
if err != nil { | |
log.Fatal("redis host isn't up: %v", err) | |
} | |
} | |
// Auth manager | |
authManager, _ := auth.NewManager( | |
config.AuthService, | |
dbStore, | |
redisClient, | |
) | |
if config.Options.CreateTokens { | |
err := cmd.CreateTokens(authManager, config) | |
if err != nil { | |
log.Fatal("create tokens: %v", err) | |
} | |
} | |
validator := valid.New() | |
// services | |
healthChecker := hc.New(redisClient, postgresEngine) | |
hcService := hcv1.NewService(authManager, healthChecker) | |
// metadata service | |
metaService := metav1.NewService(authManager, config) | |
// user service | |
userService := userv1.NewService(dbStore, authManager, validator) | |
// auth service | |
authService := authv1.NewService(dbStore, authManager, validator) | |
// wallet service | |
walletService := walletv1.NewService(dbStore, authManager) | |
bridge, err := bc.NewBridge(config.BlockchainService.Node, config.BlockchainService.Addr) | |
if err != nil { | |
log.Fatal("bridge connection failed: %v", err) | |
} | |
// bc service | |
bcService := bcv1.NewService(authManager, dbStore, bridge) | |
// grpc server | |
grpcServer, _ := grpc.New( | |
logrusEntry, | |
authManager, | |
hcService, | |
metaService, | |
authService, | |
userService, | |
bcService, | |
walletService, | |
) | |
// grpc listener | |
grpcListener, err := net.Listen("tcp", fmt.Sprintf("0.0.0.0:%d", config.Options.GrpcPort)) | |
if err != nil { | |
log.Fatal("listener: %v", err) | |
} | |
defer grpcListener.Close() | |
// grace shutdown settings | |
done := make(chan struct{}, 2) | |
stop := make(chan os.Signal, 1) | |
signal.Notify(stop, os.Interrupt) | |
// spawn grpc server thread | |
go func() { | |
log.Info("starting grpc server at port %d", config.Options.GrpcPort) | |
if err := grpcServer.Serve(grpcListener); err != nil { | |
log.Info("error shutdown grpc server: %v", err) | |
} | |
log.Info("grpc server: stopped.") | |
// send signal when server shutdown | |
done <- struct{}{} | |
}() | |
ctx := context.Background() | |
// grpc proxy server | |
var grpcProxyServer *http.Server | |
if config.Options.GrpcProxyOn { | |
var err error | |
// spawn grpc proxy server thread | |
grpcProxyServer, err = grpcproxy.NewHttpServer( | |
ctx, | |
fmt.Sprintf("0.0.0.0:%d", config.Options.GrpcPort), | |
int(config.Options.GrpcProxyPort), | |
config.Options.SwaggerUI, | |
) | |
if err != nil { | |
log.Fatal("can't create grpc proxy server: %v", err) | |
} | |
go func() { | |
log.Info("starting grpc proxy server at port %d", config.Options.GrpcProxyPort) | |
err := grpcProxyServer.ListenAndServe() | |
if err != nil && err.Error() != "http: Server closed" { | |
log.Info("error shutdown grpc proxy server: %v", err) | |
} | |
log.Info("grpc proxy server: stopped.") | |
// send signal when server shutdown | |
done <- struct{}{} | |
}() | |
} | |
// block until sig kill send signal | |
_ = <-stop | |
if config.Options.GrpcProxyOn { | |
// time to wait before forcing shutdown | |
sleepSecond := time.Duration(config.Options.ShutdownDelay) * time.Millisecond | |
// timeout context | |
ctx, cancel := context.WithTimeout(ctx, sleepSecond) | |
log.Info("shutting down grpc proxy server timeout: %v seconds", sleepSecond) | |
// shutdown service | |
if err := grpcProxyServer.Shutdown(ctx); err != nil { | |
log.Fatal("error shutting down: ", err) | |
} | |
// cancel context | |
cancel() | |
// block until grpc proxy server send done signal | |
_ = <-done | |
} | |
log.Info("shutting down grpc server") | |
grpcServer.GracefulStop() | |
// block until grpc server send done signal | |
_ = <-done | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment