Created
June 10, 2025 12:08
-
-
Save mgiacomini/ae132c5e5447db842b4a49de87cb783f to your computer and use it in GitHub Desktop.
golang DI
This file contains hidden or 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
| // main.go | |
| package main | |
| import ( | |
| "context" | |
| "errors" | |
| "log" | |
| "net/http" | |
| "os" | |
| "os/signal" | |
| "syscall" | |
| "time" | |
| "go.uber.org/zap" | |
| ) | |
| func main() { | |
| // Inicializa a aplicação usando Wire | |
| app, cleanup, err := InitializeApp() | |
| if err != nil { | |
| log.Fatal("Failed to initialize app:", err) | |
| } | |
| // Garante que a limpeza será executada | |
| defer cleanup.Execute() | |
| // Adiciona limpeza do servidor HTTP | |
| cleanup.Add(func() error { | |
| shutdownCtx, cancel := context.WithTimeout(context.Background(), 30*time.Second) | |
| defer cancel() | |
| app.Logger.Info("shutting down http server") | |
| if err := app.HTTPServer.Shutdown(shutdownCtx); err != nil { | |
| app.Logger.With(zap.Error(err)).Error("error shutting down the server") | |
| return err | |
| } | |
| return nil | |
| }) | |
| app.Logger.Info("Started HTTP server") | |
| // Canal para erros do servidor | |
| serverErrors := make(chan error, 1) | |
| // Inicia o servidor HTTP em uma goroutine | |
| go func() { | |
| app.Logger.With(zap.String("address", app.HTTPServer.Addr)).Info("HTTP server listening") | |
| if err := app.HTTPServer.ListenAndServe(); !errors.Is(err, http.ErrServerClosed) { | |
| serverErrors <- err | |
| } | |
| }() | |
| // Canal para sinais do sistema | |
| quitChannel := make(chan os.Signal, 1) | |
| signal.Notify(quitChannel, syscall.SIGINT, syscall.SIGTERM) | |
| // Aguarda erro do servidor ou sinal de shutdown | |
| select { | |
| case err := <-serverErrors: | |
| app.Logger.With(zap.Error(err)).Error("error on server") | |
| case sig := <-quitChannel: | |
| app.Logger.With(zap.String("signal", sig.String())).Info("server shutting down due to signal") | |
| } | |
| app.Logger.Info("Application shutdown complete") | |
| } |
This file contains hidden or 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
| // wire.go | |
| //go:build wireinject | |
| // +build wireinject | |
| package main | |
| import ( | |
| "context" | |
| "net/http" | |
| "github.com/google/wire" | |
| "github.com/google/uuid" | |
| "go.uber.org/zap" | |
| "your-module/config" | |
| "your-module/logger" | |
| "your-module/tracer" | |
| "your-module/jdintegrationmock" | |
| "your-module/services" | |
| "your-module/handler" | |
| "your-module/api" | |
| ) | |
| // ============================================================================= | |
| // APPLICATION STRUCT | |
| // ============================================================================= | |
| // App encapsula todas as dependências da aplicação | |
| type App struct { | |
| Config *config.Config | |
| Logger *zap.Logger | |
| Tracer *tracer.Tracer | |
| HTTPServer *http.Server | |
| Context context.Context | |
| } | |
| // Cleanup contém todas as funções de limpeza | |
| type Cleanup struct { | |
| cleanupFns []func() error | |
| } | |
| func (c *Cleanup) Add(fn func() error) { | |
| c.cleanupFns = append(c.cleanupFns, fn) | |
| } | |
| func (c *Cleanup) Execute() { | |
| for _, fn := range c.cleanupFns { | |
| if err := fn(); err != nil { | |
| // Log error se possível, mas continue a limpeza | |
| } | |
| } | |
| } | |
| // ============================================================================= | |
| // PROVIDERS | |
| // ============================================================================= | |
| // ConfigProvider carrega a configuração | |
| func ProvideConfig() (*config.Config, error) { | |
| return config.LoadConfig() | |
| } | |
| // ContextProvider cria o contexto base da aplicação | |
| func ProvideContext() context.Context { | |
| ctx, _ := context.WithCancel(context.Background()) | |
| return ctx | |
| } | |
| // LoggerProvider cria o logger configurado | |
| func ProvideLogger(cfg *config.Config) (*zap.Logger, error) { | |
| l, err := logger.NewLogger(logger.Config{ | |
| Env: cfg.DDEnv, | |
| Service: cfg.DDService, | |
| Version: cfg.DDVersion, | |
| }) | |
| if err != nil { | |
| return nil, err | |
| } | |
| l.Info("Zap logger started") | |
| return l, nil | |
| } | |
| // ServiceInstanceIDProvider gera um ID único para o serviço | |
| func ProvideServiceInstanceID() string { | |
| return uuid.NewString() | |
| } | |
| // TracerProvider cria o tracer configurado | |
| func ProvideTracer(ctx context.Context, cfg *config.Config, l *zap.Logger, serviceInstanceID string) (*tracer.Tracer, error) { | |
| // Adiciona logger ao contexto | |
| ctx = logger.WithLogger(ctx, l) | |
| t, err := tracer.NewTracer(ctx, tracer.Config{ | |
| Endpoint: cfg.OtelExporterEndpoint, | |
| SamplingRatio: cfg.OtelSamplingRatio, | |
| ServiceInstanceID: serviceInstanceID, | |
| ServiceName: cfg.OtelResourceServiceName, | |
| ServiceNamespace: cfg.OtelResourceServiceNamespace, | |
| }) | |
| if err != nil { | |
| return nil, err | |
| } | |
| if err = t.Start(ctx); err != nil { | |
| return nil, err | |
| } | |
| return t, nil | |
| } | |
| // ContextWithTracerProvider adiciona o tracer ao contexto | |
| func ProvideContextWithTracer(ctx context.Context, t *tracer.Tracer) context.Context { | |
| return tracer.WithTracer(ctx, t.OTelTracer) | |
| } | |
| // BeneficiaryRepositoryProvider cria o repository | |
| func ProvideBeneficiaryRepository() (jdintegrationmock.BeneficiaryRepository, error) { | |
| return jdintegrationmock.NewBeneficiaryRepository() | |
| } | |
| // BeneficiaryServiceProvider cria o service | |
| func ProvideBeneficiaryService(repo jdintegrationmock.BeneficiaryRepository) (*services.BeneficiaryService, error) { | |
| return services.NewBeneficiaryService(repo) | |
| } | |
| // HandlerProvider cria o handler | |
| func ProvideHandler(service *services.BeneficiaryService) (*handler.Handler, error) { | |
| return handler.NewHandler(service) | |
| } | |
| // RouterProvider cria o router | |
| func ProvideRouter(ctx context.Context, h *handler.Handler) *api.Router { | |
| return api.NewRouter(logger.Logger(ctx), h) | |
| } | |
| // HTTPServerProvider cria o servidor HTTP | |
| func ProvideHTTPServer(cfg *config.Config, router *api.Router, ctx context.Context) *http.Server { | |
| return &http.Server{ | |
| Addr: cfg.ServerAddr, | |
| Handler: router, | |
| ReadTimeout: cfg.ServerReadTimeout, | |
| WriteTimeout: cfg.ServerWriteTimeout, | |
| ReadHeaderTimeout: cfg.ServerReadTimeout, | |
| BaseContext: func(l net.Listener) context.Context { | |
| return ctx | |
| }, | |
| } | |
| } | |
| // CleanupProvider cria a estrutura de cleanup | |
| func ProvideCleanup(l *zap.Logger, t *tracer.Tracer) *Cleanup { | |
| cleanup := &Cleanup{} | |
| // Adiciona funções de limpeza | |
| cleanup.Add(func() error { | |
| l.Sync() | |
| return nil | |
| }) | |
| cleanup.Add(func() error { | |
| shutdownCtx, cancel := context.WithTimeout(context.Background(), 30*time.Second) | |
| defer cancel() | |
| l.Info("shutting down tracer") | |
| if err := t.Shutdown(shutdownCtx); err != nil { | |
| l.With(zap.Error(err)).Error("error shutting down the tracer") | |
| return err | |
| } | |
| return nil | |
| }) | |
| return cleanup | |
| } | |
| // AppProvider cria a estrutura principal da aplicação | |
| func ProvideApp( | |
| cfg *config.Config, | |
| l *zap.Logger, | |
| t *tracer.Tracer, | |
| server *http.Server, | |
| ctx context.Context, | |
| ) *App { | |
| return &App{ | |
| Config: cfg, | |
| Logger: l, | |
| Tracer: t, | |
| HTTPServer: server, | |
| Context: ctx, | |
| } | |
| } | |
| // ============================================================================= | |
| // WIRE SETS | |
| // ============================================================================= | |
| var ConfigSet = wire.NewSet( | |
| ProvideConfig, | |
| ) | |
| var LoggingSet = wire.NewSet( | |
| ProvideLogger, | |
| ProvideServiceInstanceID, | |
| ) | |
| var TracingSet = wire.NewSet( | |
| ProvideTracer, | |
| ProvideContextWithTracer, | |
| ) | |
| var RepositorySet = wire.NewSet( | |
| ProvideBeneficiaryRepository, | |
| ) | |
| var ServiceSet = wire.NewSet( | |
| ProvideBeneficiaryService, | |
| ) | |
| var HandlerSet = wire.NewSet( | |
| ProvideHandler, | |
| ) | |
| var HTTPSet = wire.NewSet( | |
| ProvideRouter, | |
| ProvideHTTPServer, | |
| ) | |
| var AppSet = wire.NewSet( | |
| ProvideContext, | |
| ProvideApp, | |
| ProvideCleanup, | |
| ) | |
| // ============================================================================= | |
| // WIRE INJECTORS | |
| // ============================================================================= | |
| // InitializeApp cria toda a aplicação com dependências injetadas | |
| func InitializeApp() (*App, *Cleanup, error) { | |
| wire.Build( | |
| ConfigSet, | |
| LoggingSet, | |
| TracingSet, | |
| RepositorySet, | |
| ServiceSet, | |
| HandlerSet, | |
| HTTPSet, | |
| AppSet, | |
| ) | |
| return nil, nil, nil | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment