(err error)
| 1364 | } |
| 1365 | |
| 1366 | func (c *closerStack) close(err error) { |
| 1367 | c.Lock() |
| 1368 | if c.closed { |
| 1369 | c.Unlock() |
| 1370 | <-c.allDone |
| 1371 | return |
| 1372 | } |
| 1373 | c.closed = true |
| 1374 | c.err = err |
| 1375 | c.Unlock() |
| 1376 | defer close(c.allDone) |
| 1377 | if len(c.closers) == 0 { |
| 1378 | return |
| 1379 | } |
| 1380 | |
| 1381 | // We are going to work down the stack in order. If things close quickly, we trigger the |
| 1382 | // closers serially, in order. `done` is a channel that indicates the nth closer is done |
| 1383 | // closing, and we should trigger the (n-1) closer. However, if things take too long we don't |
| 1384 | // want to wait, so we also start a ticker that works down the stack and sends on `done` as |
| 1385 | // well. |
| 1386 | next := len(c.closers) - 1 |
| 1387 | // here we make the buffer 2x the number of closers because we could write once for it being |
| 1388 | // actually done and once via the countdown for each closer |
| 1389 | done := make(chan int, len(c.closers)*2) |
| 1390 | startNext := func() { |
| 1391 | go func(i int) { |
| 1392 | defer func() { done <- i }() |
| 1393 | cwn := c.closers[i] |
| 1394 | cErr := cwn.closer.Close() |
| 1395 | c.logger.Debug(context.Background(), |
| 1396 | "closed item from stack", slog.F("name", cwn.name), slog.Error(cErr)) |
| 1397 | }(next) |
| 1398 | next-- |
| 1399 | } |
| 1400 | done <- len(c.closers) // kick us off right away |
| 1401 | |
| 1402 | // start a ticking countdown in case we hang/don't close quickly |
| 1403 | countdown := len(c.closers) - 1 |
| 1404 | ctx, cancel := context.WithCancel(context.Background()) |
| 1405 | defer cancel() |
| 1406 | c.clock.TickerFunc(ctx, gracefulShutdownTimeout, func() error { |
| 1407 | if countdown < 0 { |
| 1408 | return nil |
| 1409 | } |
| 1410 | done <- countdown |
| 1411 | countdown-- |
| 1412 | return nil |
| 1413 | }, "closerStack") |
| 1414 | |
| 1415 | for n := range done { // the nth closer is done |
| 1416 | if n == 0 { |
| 1417 | return |
| 1418 | } |
| 1419 | if n-1 == next { |
| 1420 | startNext() |
| 1421 | } |
| 1422 | } |
| 1423 | } |
no test coverage detected