package app import ( "errors" "sync" "github.com/rs/zerolog" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/codes" "gitea.libretechconsulting.com/rmcguire/go-app/pkg/config" ) func (a *App) Done() <-chan any { return a.appDone } func (a *App) MustRun() { if a.cfg != nil { panic(errors.New("already ran app trying to run")) } // Set up app a.cfg = config.MustFromCtx(a.AppContext) a.l = zerolog.Ctx(a.AppContext) a.shutdownFuncs = make([]shutdownFunc, 0) a.appDone = make(chan any) a.HTTP.HTTPDone = make(chan any) if !a.cfg.HTTPEnabled() && !a.cfg.GRPCEnabled() { panic(errors.New("neither http nor grpc enabled, nothing to do")) } if len(a.HTTP.Funcs) < 1 { a.l.Warn().Msg("no http funcs provided, only serving health and metrics") } // Start OTEL // Registers a NO-OP provider if not enabled a.initOTEL() ctx, initSpan := a.tracer.Start(a.AppContext, "init") defer initSpan.End() var serverWG sync.WaitGroup // Start HTTP (does not block) if a.cfg.HTTPEnabled() { serverWG.Add(1) go func() { defer serverWG.Done() if err := a.initHTTP(ctx); err != nil { initSpan.RecordError(err) initSpan.SetStatus(codes.Error, err.Error()) } initSpan.AddEvent("http server started") initSpan.SetAttributes(attribute.Int("http.handlers", len(a.HTTP.Funcs))) }() } // Start GRPC (does not block) if a.cfg.GRPCEnabled() { serverWG.Add(1) go func() { defer serverWG.Done() if err := a.initGRPC(ctx); err != nil { initSpan.RecordError(err) initSpan.SetStatus(codes.Error, err.Error()) } initSpan.AddEvent("grpc server started") initSpan.SetAttributes(attribute.Int("grpc.services", len(a.GRPC.Services))) }() } serverWG.Wait() // Monitor app lifecycle go a.run() // Startup Complete a.l.Info(). Str("name", a.cfg.Name). Str("version", a.cfg.Version). Str("logLevel", a.cfg.Logging.Level). Msg("app initialized") initSpan.SetStatus(codes.Ok, "") }