package tache | |
import ( | |
"runtime" | |
"sync" | |
"time" | |
) | |
// sliceContains checks if a slice contains a value | |
func sliceContains[T comparable](slice []T, v T) bool { | |
for _, vv := range slice { | |
if vv == v { | |
return true | |
} | |
} | |
return false | |
} | |
// getCurrentGoroutineStack get current goroutine stack | |
func getCurrentGoroutineStack() string { | |
buf := make([]byte, 1<<16) | |
n := runtime.Stack(buf, false) | |
return string(buf[:n]) | |
} | |
// newDebounce returns a debounced function | |
func newDebounce(f func(), interval time.Duration) func() { | |
var timer *time.Timer | |
var lock sync.Mutex | |
return func() { | |
lock.Lock() | |
defer lock.Unlock() | |
if timer == nil { | |
timer = time.AfterFunc(interval, f) | |
} else { | |
timer.Reset(interval) | |
} | |
} | |
} | |
// isRetry checks if a task is retry executed | |
func isRetry[T Task](task T) bool { | |
return task.GetState() == StateWaitingRetry | |
} | |
// isLastRetry checks if a task is last retry | |
func isLastRetry[T Task](task T) bool { | |
retry, maxRetry := task.GetRetry() | |
return retry >= maxRetry | |
} | |
// needRetry judge whether the task need retry | |
func needRetry[T Task](task T) bool { | |
// if task is not recoverable, return false | |
if !IsRecoverable(task.GetErr()) { | |
return false | |
} | |
// if task is not retryable, return false | |
if r, ok := Task(task).(Retryable); ok && !r.Retryable() { | |
return false | |
} | |
// only retry when task is errored or failed | |
if sliceContains([]State{StateErrored, StateFailed}, task.GetState()) { | |
retry, maxRetry := task.GetRetry() | |
if retry < maxRetry { | |
task.SetRetry(retry+1, maxRetry) | |
task.SetState(StateWaitingRetry) | |
return true | |
} | |
} | |
return false | |
} | |