55 lines
1.1 KiB
Go
55 lines
1.1 KiB
Go
package common
|
|
|
|
import (
|
|
"time"
|
|
)
|
|
|
|
type InterruptibleTaskResult struct {
|
|
Err error
|
|
IsCancelled bool
|
|
}
|
|
|
|
type InterruptibleTask struct {
|
|
IsCancelled func() bool
|
|
Task func(cancelCh <-chan struct{}) error
|
|
}
|
|
|
|
func NewInterruptibleTask(isCancelled func() bool, task func(cancelCh <-chan struct{}) error) *InterruptibleTask {
|
|
return &InterruptibleTask{
|
|
IsCancelled: isCancelled,
|
|
Task: task,
|
|
}
|
|
}
|
|
|
|
func StartInterruptibleTask(isCancelled func() bool, task func(cancelCh <-chan struct{}) error) InterruptibleTaskResult {
|
|
t := NewInterruptibleTask(isCancelled, task)
|
|
return t.Run()
|
|
}
|
|
|
|
func (s *InterruptibleTask) Run() InterruptibleTaskResult {
|
|
completeCh := make(chan error)
|
|
|
|
cancelCh := make(chan struct{})
|
|
defer close(cancelCh)
|
|
|
|
go func() {
|
|
err := s.Task(cancelCh)
|
|
completeCh <- err
|
|
|
|
// senders close, receivers check for close
|
|
close(completeCh)
|
|
}()
|
|
|
|
for {
|
|
if s.IsCancelled() {
|
|
return InterruptibleTaskResult{Err: nil, IsCancelled: true}
|
|
}
|
|
|
|
select {
|
|
case err := <-completeCh:
|
|
return InterruptibleTaskResult{Err: err, IsCancelled: false}
|
|
case <-time.After(100 * time.Millisecond):
|
|
}
|
|
}
|
|
}
|