closeWithError closes the provisioner; subsequent reads/writes will return the error err.
(err error)
| 670 | |
| 671 | // closeWithError closes the provisioner; subsequent reads/writes will return the error err. |
| 672 | func (p *Server) closeWithError(err error) error { |
| 673 | p.mutex.Lock() |
| 674 | var activeJob *runner.Runner |
| 675 | first := false |
| 676 | if !p.closingB { |
| 677 | first = true |
| 678 | p.closingB = true |
| 679 | // only the first caller to close should attempt to fail the active job |
| 680 | activeJob = p.activeJob |
| 681 | } |
| 682 | // don't hold the mutex while doing I/O. |
| 683 | p.mutex.Unlock() |
| 684 | if activeJob != nil { |
| 685 | errMsg := "provisioner daemon was shutdown gracefully" |
| 686 | if err != nil { |
| 687 | errMsg = err.Error() |
| 688 | } |
| 689 | p.opts.Logger.Debug(p.closeContext, "failing active job because of close") |
| 690 | ctx, cancel := context.WithTimeout(context.Background(), time.Second) |
| 691 | defer cancel() |
| 692 | failErr := activeJob.Fail(ctx, &proto.FailedJob{Error: errMsg}) |
| 693 | if failErr != nil { |
| 694 | activeJob.ForceStop() |
| 695 | } |
| 696 | if err == nil { |
| 697 | err = failErr |
| 698 | } |
| 699 | } |
| 700 | |
| 701 | if first { |
| 702 | p.closeCancel() |
| 703 | p.opts.Logger.Debug(context.Background(), "waiting for goroutines to exit") |
| 704 | p.wg.Wait() |
| 705 | p.opts.Logger.Debug(context.Background(), "closing server with error", slog.Error(err)) |
| 706 | p.closeError = err |
| 707 | close(p.closedCh) |
| 708 | return err |
| 709 | } |
| 710 | p.opts.Logger.Debug(p.closeContext, "waiting for first closer to complete") |
| 711 | <-p.closedCh |
| 712 | p.opts.Logger.Debug(p.closeContext, "first closer completed") |
| 713 | return p.closeError |
| 714 | } |