How to repetitively run a function until it returns true or timeout?

Issue

I have a function checkSuccess() which return true if the task have finished.

I’d like to call checkSuccess() every 1 second and break until it return true or timeout.

What I’m having now is to use a goroutine to run a for loop, in which I call checkSuccess() every 1 second. And in the main process, I use time.After to check if the whole checking duration has passed timeout.

func myfunc (timeout time.Duration) {

    successChan := make(chan struct{})
    timeoutChan := make(chan struct{})

    // Keep listening to the task.
    go func() {
        for {
            select {
            // Exit the forloop if the timeout has been reached
            case <-timeoutChan:
                return
            default:
            }
            // Early exit if task has succeed.
            if checkSuccess() {
                close(successChan)
                return
            }
        time.Sleep(time.Second)
        }
    }()

    // Once timeout, stop listening to the task.
    select {
    case <-time.After(timeout):
        close(timeoutChan)
        return 
    case <-successChan:
        return
    }

    return
}

It actually has achieved my goal, but I found it very tedious. Is there any better (shorter) way to write it?

Solution

You don’t need a separate goroutine or channels:

func myfunc (timeout time.Duration) {
   ticker:=time.NewTicker(time.Second)
   defer ticker.Close()
   to:=time.NewTimer(timeout)
   defer to.Stop()
   for {
      select {
         case <-to.C:
           return // timeout
         case <-ticker:
           if checkSuccess() {
             return
           }
      }
   }
}

Answered By – Burak Serdar

Answer Checked By – Marie Seifert (GoLangFix Admin)

Leave a Reply

Your email address will not be published.