55 "context"
66 "errors"
77 "io"
8- "sync"
8+ "sync/atomic "
99
1010 "github.com/go-modkit/modkit/modkit/module"
1111)
@@ -16,8 +16,8 @@ type App struct {
1616 Graph * Graph
1717 container * Container
1818 Controllers map [string ]any
19- closeOnce sync. Once
20- closeErr error
19+ closed atomic. Bool
20+ closing atomic. Bool
2121}
2222
2323func controllerKey (moduleName , controllerName string ) string {
@@ -98,20 +98,32 @@ func (a *App) Close() error {
9898
9999// CloseContext closes providers implementing io.Closer in reverse build order.
100100func (a * App ) CloseContext (ctx context.Context ) error {
101- a .closeOnce .Do (func () {
102- closers := a .container .closersLIFO ()
103- var errs []error
104- for _ , closer := range closers {
105- if err := closer .Close (); err != nil {
106- errs = append (errs , err )
107- }
108- }
109- if ctx != nil && ctx .Err () != nil {
110- errs = append (errs , ctx .Err ())
101+ if a .closed .Load () {
102+ return nil
103+ }
104+
105+ if err := ctx .Err (); err != nil {
106+ return err
107+ }
108+
109+ if ! a .closing .CompareAndSwap (false , true ) {
110+ return nil
111+ }
112+ defer a .closing .Store (false )
113+
114+ var errs []error
115+ for _ , closer := range a .container .closersLIFO () {
116+ if err := ctx .Err (); err != nil {
117+ return err
111118 }
112- if len ( errs ) > 0 {
113- a . closeErr = errors . Join (errs ... )
119+ if err := closer . Close (); err != nil {
120+ errs = append (errs , err )
114121 }
115- })
116- return a .closeErr
122+ }
123+ if len (errs ) == 0 {
124+ a .closed .Store (true )
125+ return nil
126+ }
127+ a .closed .Store (true )
128+ return errors .Join (errs ... )
117129}
0 commit comments