@@ -12,6 +12,7 @@ import (
1212 "strings"
1313
1414 "github.com/gorilla/mux"
15+ "go.opentelemetry.io/otel"
1516 "golang.org/x/sync/errgroup"
1617
1718 "gofr.dev/pkg/gofr/config"
@@ -21,12 +22,15 @@ import (
2122 "gofr.dev/pkg/gofr/metrics"
2223 "gofr.dev/pkg/gofr/migration"
2324 "gofr.dev/pkg/gofr/service"
25+ "gofr.dev/pkg/gofr/version"
2426)
2527
2628const (
2729 configLocation = "./configs"
2830)
2931
32+ var errStartupHookPanic = errors .New ("startup hook panicked" )
33+
3034// App is the main application in the GoFr framework.
3135type App struct {
3236 // Config can be used by applications to fetch custom configurations from environment or file.
@@ -50,16 +54,36 @@ type App struct {
5054}
5155
5256func (a * App ) runOnStartHooks (ctx context.Context ) error {
57+ // Create a span for the startup hooks execution,
58+ tr := otel .GetTracerProvider ().Tracer ("gofr-" + version .Framework )
59+
60+ ctx , span := tr .Start (ctx , "startup-hooks" )
61+ defer span .End ()
62+
5363 // Use the existing newContext function with noopRequest
5464 gofrCtx := newContext (nil , noopRequest {}, a .container )
5565
5666 // Set the context for cancellation support
5767 gofrCtx .Context = ctx
5868
59- for _ , hook := range a .onStartHooks {
60- if err := hook (gofrCtx ); err != nil {
61- a .Logger ().Errorf ("OnStart hook failed: %v" , err )
62- return err
69+ for i , hook := range a .onStartHooks {
70+ // Add panic recovery to prevent entire application crash
71+ var hookErr error
72+
73+ func () {
74+ defer func () {
75+ if r := recover (); r != nil {
76+ a .Logger ().Errorf ("OnStart hook %d panicked: %v" , i , r )
77+ hookErr = fmt .Errorf ("hook %d: %w: %v" , i , errStartupHookPanic , r )
78+ }
79+ }()
80+
81+ hookErr = hook (gofrCtx )
82+ }()
83+
84+ if hookErr != nil {
85+ a .Logger ().Errorf ("OnStart hook failed: %v" , hookErr )
86+ return hookErr
6387 }
6488
6589 // Check if context was canceled
0 commit comments