Skip to content

Commit

Permalink
[IMPROVEMENT] use Wire for component connection in DI
Browse files Browse the repository at this point in the history
  • Loading branch information
bardia-heydari committed Jul 24, 2019
1 parent 5bb3860 commit df2edc4
Show file tree
Hide file tree
Showing 12 changed files with 206 additions and 109 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ mocks
.coverage
*.cover
/coverage.html
.idea
.idea
**/wire_gen.go
6 changes: 5 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ MOCKED_FOLDERS = $(patsubst %,%/mocks,$(MOCK_PACKAGES))
help: ## Display this help screen
@grep -h -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'

generate: $(PBS) $(MOCKED_FILES) $(MOCKED_FOLDERS) | .remove_empty_dirs ## Generate all auto-generated files
generate: $(PBS) $(MOCKED_FILES) $(MOCKED_FOLDERS) cmd/postviewd/wire_gen.go | .remove_empty_dirs ## Generate all auto-generated files
.remove_empty_dirs:
-find . -type d -print | xargs rmdir 2>/dev/null | true

Expand Down Expand Up @@ -71,6 +71,9 @@ coverage.cover: $(SRCS) $(PBS) Makefile | generate
echo "mode: count" > $@
grep -h -v "^mode:" .coverage/*.cover >> $@

cmd/postviewd/wire_gen.go: cmd/postviewd/container.go
wire ./cmd/postviewd

.SECONDEXPANSION:
$(PBS): $$(patsubst %.pb.go,%.proto,$$(patsubst pkg%,api%,$$@)) | .pre-check-go
$(PROTOC) $(PROTOC_OPTIONS) --go_out=plugins=grpc:$(GOPATH)/src ./$<
Expand All @@ -88,6 +91,7 @@ $(MOCKED_FILES): $$(shell find $$(patsubst %/mocks,%,$$(patsubst %/mocks/,%,$$(d
if [ -z "$$(which protoc-gen-go)" ]; then go get -v github.com/golang/protobuf/protoc-gen-go; fi
if [ -z "$$(which mockery)" ]; then go get -v github.com/vektra/mockery/cmd/mockery; fi
if [ -z "$$(which gocov)" ]; then go get -v github.com/axw/gocov/gocov; fi
if [ -z "$$(which wire)" ]; then go get -v github.com/google/wire/cmd/wire; fi

# Variables
ROOT := git.cafebazaar.ir/arcana261/golang-boilerplate
Expand Down
10 changes: 10 additions & 0 deletions cmd/postviewd/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"strings"
"time"

"git.cafebazaar.ir/arcana261/golang-boilerplate/pkg/errors"

"git.cafebazaar.ir/arcana261/golang-boilerplate/pkg/sql"
"github.com/spf13/cobra"
"github.com/spf13/viper"
Expand Down Expand Up @@ -102,3 +104,11 @@ func LoadConfig(cmd *cobra.Command) (*Config, error) {

return &config, nil
}

func provideConfig(cmd *cobra.Command) (*Config, error) {
config, err := LoadConfig(cmd)
if err != nil {
return nil, errors.Wrap(err, "Failed to load configurations.")
}
return config, nil
}
33 changes: 33 additions & 0 deletions cmd/postviewd/container.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//+build wireinject

package main

import (
"context"
"git.cafebazaar.ir/arcana261/golang-boilerplate/internal/app/core"
"git.cafebazaar.ir/arcana261/golang-boilerplate/internal/pkg/grpcserver"
"git.cafebazaar.ir/arcana261/golang-boilerplate/internal/pkg/provider"
"github.com/google/wire"
"github.com/spf13/cobra"
)

func CreateServer(ctx context.Context, cmd *cobra.Command) (*grpcserver.Server, error) {
panic(wire.Build(
provideConfig,
provideLogger,
provideProvider,
provideCache,
providePrometheus,
provideServer,
core.New,
))
}

func CreateProvider(ctx context.Context, cmd *cobra.Command) (provider.PostProvider, error) {
panic(wire.Build(
provideConfig,
provideLogger,
provideProvider,
providePrometheus,
))
}
19 changes: 10 additions & 9 deletions cmd/postviewd/logging.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,21 @@ const (
)

// ConfigureLogging handlerconfig logger based on the given configuration
func configureLogging(config *LoggingConfig) error {
if config.Level != "" {
level, err := logrus.ParseLevel(config.Level)
func provideLogger(config *Config) (*logrus.Logger, error) {
logger := logrus.New()
if config.Logging.Level != "" {
level, err := logrus.ParseLevel(config.Logging.Level)
if err != nil {
return err
return nil, err
}
logrus.SetLevel(level)
logger.SetLevel(level)
}

logrus.SetFormatter(&logrus.JSONFormatter{
logger.SetFormatter(&logrus.JSONFormatter{
DisableTimestamp: false,
})

if config.SentryEnabled {
if config.Logging.SentryEnabled {

hook, err := logrus_sentry.NewAsyncSentryHook(sentryDSN, []logrus.Level{
logrus.PanicLevel,
Expand All @@ -46,8 +47,8 @@ func configureLogging(config *LoggingConfig) error {

hook.StacktraceConfiguration.Enable = true

logrus.AddHook(hook)
logger.AddHook(hook)
}

return nil
return logger, nil
}
7 changes: 4 additions & 3 deletions cmd/postviewd/migrate.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,11 @@ func init() {

func migrateDatabase(cmd *cobra.Command, args []string) {
printVersion()
config := loadConfigOrPanic(cmd)
configureLoggerOrPanic(config.Logging)

providerInstance := getProvider(config)
ctx, _ := makeServerCtx()

providerInstance, err := CreateProvider(ctx, cmd)
panicWithError(err, "fail to create provider")
migrater, ok := providerInstance.(sql.Migrater)
if ok {
err := migrater.Migrate()
Expand Down
4 changes: 4 additions & 0 deletions cmd/postviewd/prometheus.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,7 @@ func init() {
postProviderMetrics = prometheus.NewHistogram("divar_post_view_provider",
"view metrics about post provider", "provider_type", "method", "ok", "success")
}

func providePrometheus(config *Config) *prometheus.Server {
return prometheus.NewServer(config.MetricListenPort)
}
120 changes: 25 additions & 95 deletions cmd/postviewd/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,35 +3,28 @@ package main
import (
"context"
"fmt"
"git.cafebazaar.ir/arcana261/golang-boilerplate/pkg/cache"
"git.cafebazaar.ir/arcana261/golang-boilerplate/pkg/cache/adaptors"
"git.cafebazaar.ir/arcana261/golang-boilerplate/pkg/cache/middlewares"
"git.cafebazaar.ir/arcana261/golang-boilerplate/pkg/cache/multilayercache"
"github.com/allegro/bigcache"
"git.cafebazaar.ir/arcana261/golang-boilerplate/internal/pkg/grpcserver"
"git.cafebazaar.ir/arcana261/golang-boilerplate/internal/pkg/metrics/prometheus"
"git.cafebazaar.ir/arcana261/golang-boilerplate/pkg/postview"
"log"
"net"
"net/http"
"os"
"os/signal"
"sync"
"syscall"

"git.cafebazaar.ir/arcana261/golang-boilerplate/pkg/postview"
"git.cafebazaar.ir/arcana261/golang-boilerplate/pkg/cache"
"git.cafebazaar.ir/arcana261/golang-boilerplate/pkg/cache/adaptors"
"git.cafebazaar.ir/arcana261/golang-boilerplate/pkg/cache/middlewares"
"git.cafebazaar.ir/arcana261/golang-boilerplate/pkg/cache/multilayercache"
"git.cafebazaar.ir/arcana261/golang-boilerplate/pkg/errors"
"github.com/allegro/bigcache"

"github.com/go-redis/redis"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"

"git.cafebazaar.ir/arcana261/golang-boilerplate/internal/app/core"
"git.cafebazaar.ir/arcana261/golang-boilerplate/internal/pkg/provider"
"git.cafebazaar.ir/arcana261/golang-boilerplate/pkg/errors"
"git.cafebazaar.ir/arcana261/golang-boilerplate/pkg/sql"
"google.golang.org/grpc"

grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
grpc_logrus "github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus"
grpc_recovery "github.com/grpc-ecosystem/go-grpc-middleware/recovery"
grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus"
)

var serveCmd = &cobra.Command{
Expand All @@ -47,34 +40,19 @@ func init() {
func serve(cmd *cobra.Command, args []string) {
printVersion()

config := loadConfigOrPanic(cmd)

configureLoggerOrPanic(config.Logging)

prometheusMetricServer := startPrometheusMetricServerOrPanic(config.MetricListenPort)
defer shutdownPrometheusMetricServerOrPanic(prometheusMetricServer)

providerInstance := getProvider(config)
cacheInstance := getCache(config)
servicer := core.New(providerInstance, cacheInstance)

listener, err := net.Listen("tcp", fmt.Sprintf(":%d", config.ListenPort))
if err != nil {
panicWithError(err, "failed to listen")
}

grpcServer := configureServer(config)
postview.RegisterPostViewServer(grpcServer, servicer)

serverCtx, serverCancel := makeServerCtx()
defer serverCancel()

server, err := CreateServer(serverCtx, cmd)
panicWithError(err, "failed to create server")

var serverWaitGroup sync.WaitGroup

serverWaitGroup.Add(1)
go func() {
defer serverWaitGroup.Done()

if err := grpcServer.Serve(listener); err != nil {
if err := server.Serve(); err != nil {
panicWithError(err, "failed to serve")
}
}()
Expand All @@ -85,12 +63,16 @@ func serve(cmd *cobra.Command, args []string) {

<-serverCtx.Done()

grpcServer.GracefulStop()
server.Stop()

serverWaitGroup.Wait()
}

func getProvider(config *Config) provider.PostProvider {
func provideServer(server postview.PostViewServer, config *Config, logger *logrus.Logger) (*grpcserver.Server, error) {
return grpcserver.New(server, logger, config.ListenPort)
}

func provideProvider(config *Config, logger *logrus.Logger, prometheusMetric *prometheus.Server) provider.PostProvider {
db, err := sql.GetDatabase(config.Database)
if err != nil {
logrus.WithError(err).WithField(
Expand All @@ -107,7 +89,7 @@ func getProvider(config *Config) provider.PostProvider {
return providerInstance
}

func getCache(config *Config) cache.Layer {
func provideCache(config *Config, prometheusMetric *prometheus.Server) (cache.Layer, error) {
var cacheLayers []cache.Layer
if config.Cache.Redis.Enabled {
redisClient := redis.NewClient(&redis.Options{
Expand All @@ -117,7 +99,7 @@ func getCache(config *Config) cache.Layer {
// Ping Redis
err := redisClient.Ping().Err()
if err != nil {
panicWithError(err, "fail to connect to redis")
return nil, errors.Wrap(err, "fail to connect to redis")
}
cacheLayers = append(cacheLayers, adaptors.NewRedisAdaptor(config.Cache.Redis.ExpirationTime, redisClient))

Expand All @@ -133,7 +115,7 @@ func getCache(config *Config) cache.Layer {
HardMaxCacheSize: config.Cache.BigCache.HardMaxCacheSize,
})
if err != nil {
panicWithError(err, "fail to initialize big cache")
return nil, errors.Wrap(err, "fail to initialize big cache")
}

cacheLayers = append(cacheLayers, adaptors.NewBigCacheAdaptor(bigCacheInstance))
Expand All @@ -147,36 +129,7 @@ func getCache(config *Config) cache.Layer {
"cache_type": "multilayer",
}))

return cacheInstance
}

func configureServer(config *Config) *grpc.Server {
logEntry := logrus.WithFields(map[string]interface{}{
"app": "postviewd",
})

interceptors := []grpc.UnaryServerInterceptor{
grpc_logrus.UnaryServerInterceptor(logEntry),
errors.UnaryServerInterceptor,
grpc_prometheus.UnaryServerInterceptor,
grpc_recovery.UnaryServerInterceptor(),
}

return grpc.NewServer(grpc.UnaryInterceptor(grpc_middleware.ChainUnaryServer(interceptors...)))
}

func loadConfigOrPanic(cmd *cobra.Command) *Config {
config, err := LoadConfig(cmd)
if err != nil {
panicWithError(err, "Failed to load configurations.")
}
return config
}

func configureLoggerOrPanic(loggerConfig LoggingConfig) {
if err := configureLogging(&loggerConfig); err != nil {
panicWithError(err, "Failed to configure logger.")
}
return cacheInstance, nil
}

func makeServerCtx() (context.Context, context.CancelFunc) {
Expand All @@ -195,29 +148,6 @@ func makeServerCtx() (context.Context, context.CancelFunc) {
return ctx, cancel
}

func startPrometheusMetricServerOrPanic(listenPort int) *http.Server {
server := &http.Server{
Addr: fmt.Sprintf(":%d", listenPort),
Handler: promhttp.Handler(),
}

go listenAndServePrometheusMetrics(server)

return server
}

func listenAndServePrometheusMetrics(server *http.Server) {
if err := server.ListenAndServe(); err != nil {
panicWithError(err, "failed to start liveness http probe listener")
}
}

func shutdownPrometheusMetricServerOrPanic(server *http.Server) {
if err := server.Shutdown(context.Background()); err != nil {
panicWithError(err, "Failed to shutdown prometheus metric server")
}
}

func declareReadiness() error {
// nolint: gosec
file, err := os.Create("/tmp/readiness")
Expand Down
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ module git.cafebazaar.ir/arcana261/golang-boilerplate

require (
github.com/allegro/bigcache v1.2.1
github.com/axw/gocov v1.0.0 // indirect
github.com/certifi/gocertifi v0.0.0-20190506164543-d2eda7129713 // indirect
github.com/evalphobia/logrus_sentry v0.8.2
github.com/getsentry/raven-go v0.2.0
github.com/go-logfmt/logfmt v0.4.0 // indirect
github.com/go-redis/redis v6.15.2+incompatible
github.com/golang/protobuf v1.3.1
github.com/google/wire v0.3.0
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0
github.com/jinzhu/gorm v1.9.8
Expand Down
Loading

0 comments on commit df2edc4

Please sign in to comment.