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 }