Conditional Timeout

旧时模样 提交于 2021-02-16 20:58:46

问题


I have some code, there are 3 timers,

  • GracefulExecutionTimeout - total running time
  • WaitTimeout - time to initial wait for first message
  • IdleTimeout - time to wait for subsequent messages

If any of the timers are reached the app should cleanly exit. I have it working below

msgs := make(chan string)

go func() {
    time.Sleep(time.Second)
    msgs <- "test"
}()
// graceful max execution time
gracefulMaxTimeout := time.Second * time.Duration(10)
gracefulMaxTimer := time.NewTimer(gracefulMaxTimeout)

// idleTimeout
idleTimeout := time.Second * time.Duration(5)
idleTimer := time.NewTimer(idleTimeout)

// waitTimeout
waitTimeout := time.Second * time.Duration(2)
waitTimer := time.NewTimer(waitTimeout)
for {
    select {
    case <-gracefulMaxTimer.C:
        fmt.Println("GracefulMaxExecutionTimeout Reached")

        // graceful exit
        os.Exit(0)
    case <-idleTimer.C:
        fmt.Println("IdleTimeout Reached")

        // graceful exit
        os.Exit(0)
    case <-waitTimer.C:
        fmt.Println("WaitTimeout Reached")
        // graceful exit
        os.Exit(0)
    case msg := <-msgs:
        // stop wait timer
        waitTimer.Stop()
        fmt.Println(msg)

        // Reset idle timer
        if !idleTimer.Stop() {
            <-idleTimer.C
        }
        fmt.Println("IdleIimeout Reset")
        idleTimer.Reset(idleTimeout)
    }
}

Go Playground

I want to make the WaitTimeout optional but not sure how to approach it. If i surround the construction of the waitTimer with an if statement then it wont work as the waitTimer isnt defined for the select statement ... How can i make the WaitTimeout conditional ?

I can just .Stop() the timer after its created but that seems a little dirty ...


回答1:


You may declare the wait timer and its channel outside the if statement, and only initialize them if wait timer is needed. If not, the channel may remain its zero value–which is nil–because receiving from a nil channel blocks forever, so this case will never be ready (for details, see How does a non initialized channel behave?).

useWaitTimer := true

var (
    waitTimer  *time.Timer
    waitTimerC <-chan time.Time
)
if useWaitTimer {
    waitTimeout := time.Millisecond * time.Duration(500)
    waitTimer = time.NewTimer(waitTimeout)
    waitTimerC = waitTimer.C
}

// ...

for {
    select {
    // ...

    case <-waitTimerC:
        fmt.Println("WaitTimeout Reached")
        // graceful exit
        os.Exit(0)

    // ...
    }
}

Then of course you can only reset the wait timer if it exists, this must also be checked (and don't forget to drain the channel if it returns false):

// stop wait timer if exists
if waitTimer != nil && !waitTimer.Stop() {
    <-waitTimerC
}

Try it on the Go Playground.



来源:https://stackoverflow.com/questions/61408256/conditional-timeout

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!