github.com/mmcquillan/packer@v1.1.1-0.20171009221028-c85cf0483a5d/builder/azure/common/interruptible_task.go (about)

     1  package common
     2  
     3  import (
     4  	"time"
     5  )
     6  
     7  type InterruptibleTaskResult struct {
     8  	Err         error
     9  	IsCancelled bool
    10  }
    11  
    12  type InterruptibleTask struct {
    13  	IsCancelled func() bool
    14  	Task        func(cancelCh <-chan struct{}) error
    15  }
    16  
    17  func NewInterruptibleTask(isCancelled func() bool, task func(cancelCh <-chan struct{}) error) *InterruptibleTask {
    18  	return &InterruptibleTask{
    19  		IsCancelled: isCancelled,
    20  		Task:        task,
    21  	}
    22  }
    23  
    24  func StartInterruptibleTask(isCancelled func() bool, task func(cancelCh <-chan struct{}) error) InterruptibleTaskResult {
    25  	t := NewInterruptibleTask(isCancelled, task)
    26  	return t.Run()
    27  }
    28  
    29  func (s *InterruptibleTask) Run() InterruptibleTaskResult {
    30  	completeCh := make(chan error)
    31  
    32  	cancelCh := make(chan struct{})
    33  	defer close(cancelCh)
    34  
    35  	go func() {
    36  		err := s.Task(cancelCh)
    37  		completeCh <- err
    38  
    39  		// senders close, receivers check for close
    40  		close(completeCh)
    41  	}()
    42  
    43  	for {
    44  		if s.IsCancelled() {
    45  			return InterruptibleTaskResult{Err: nil, IsCancelled: true}
    46  		}
    47  
    48  		select {
    49  		case err := <-completeCh:
    50  			return InterruptibleTaskResult{Err: err, IsCancelled: false}
    51  		case <-time.After(100 * time.Millisecond):
    52  		}
    53  	}
    54  }