2020-06-05 07:57:11 +03:00
|
|
|
/*
|
|
|
|
* @Description: https://github.com/crazybber
|
|
|
|
* @Author: Edward
|
|
|
|
* @Date: 2020-06-05 12:43:39
|
|
|
|
* @Last Modified by: Edward
|
2020-06-05 12:36:30 +03:00
|
|
|
* @Last Modified time: 2020-06-05 17:34:37
|
2020-06-05 07:57:11 +03:00
|
|
|
*/
|
|
|
|
|
2020-06-05 12:36:30 +03:00
|
|
|
// Package deadline implements deadline (also known as "timeout") resiliency pattern for Go.
|
2020-05-03 05:53:23 +03:00
|
|
|
package deadline
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
2020-06-05 12:36:30 +03:00
|
|
|
// ErrTimedOut is the error returned from Run when the Worker expires.
|
2020-05-03 05:53:23 +03:00
|
|
|
var ErrTimedOut = errors.New("timed out waiting for function to finish")
|
|
|
|
|
2020-06-05 12:36:30 +03:00
|
|
|
// Worker implements the Deadline/timeout resiliency pattern.
|
|
|
|
// worker do the target job
|
|
|
|
type Worker struct {
|
2020-05-03 05:53:23 +03:00
|
|
|
timeout time.Duration
|
2020-06-05 07:57:11 +03:00
|
|
|
action string
|
2020-05-03 05:53:23 +03:00
|
|
|
}
|
|
|
|
|
2020-06-05 12:36:30 +03:00
|
|
|
// New create a new Worker with the given timeout.and tile
|
|
|
|
func New(timeout time.Duration, someActionTitle string) *Worker {
|
|
|
|
return &Worker{
|
2020-05-03 05:53:23 +03:00
|
|
|
timeout: timeout,
|
2020-06-05 12:36:30 +03:00
|
|
|
action: someActionTitle,
|
2020-05-03 05:53:23 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-05 12:36:30 +03:00
|
|
|
// Run runs the given function, passing it a stopper channel. If the Worker passes before
|
2020-05-03 05:53:23 +03:00
|
|
|
// the function finishes executing, Run returns ErrTimeOut to the caller and closes the stopper
|
|
|
|
// channel so that the work function can attempt to exit gracefully. It does not (and cannot)
|
|
|
|
// simply kill the running function, so if it doesn't respect the stopper channel then it may
|
2020-06-05 12:36:30 +03:00
|
|
|
// keep running after the Worker passes. If the function finishes before the Worker, then
|
2020-05-03 05:53:23 +03:00
|
|
|
// the return value of the function is returned from Run.
|
2020-06-05 12:36:30 +03:00
|
|
|
func (d *Worker) Run(work func(stopperSignal chan error) error) error {
|
2020-06-05 07:57:11 +03:00
|
|
|
|
2020-06-05 12:36:30 +03:00
|
|
|
result := make(chan error)
|
|
|
|
//we can stop the work in advance
|
|
|
|
stopper := make(chan error, 1)
|
2020-05-03 05:53:23 +03:00
|
|
|
|
|
|
|
go func() {
|
|
|
|
value := work(stopper)
|
|
|
|
select {
|
|
|
|
case result <- value:
|
2020-06-05 12:36:30 +03:00
|
|
|
case stopError := <-stopper:
|
|
|
|
result <- stopError
|
2020-05-03 05:53:23 +03:00
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
2020-06-05 07:57:11 +03:00
|
|
|
//handle result
|
|
|
|
|
2020-05-03 05:53:23 +03:00
|
|
|
select {
|
|
|
|
case ret := <-result:
|
|
|
|
return ret
|
|
|
|
case <-time.After(d.timeout):
|
|
|
|
close(stopper)
|
|
|
|
return ErrTimedOut
|
|
|
|
}
|
|
|
|
}
|