Условный тайм-аут - PullRequest
       8

Условный тайм-аут

2 голосов
/ 24 апреля 2020

У меня есть какой-то код, есть 3 таймера,

  • GracefulExecutionTimeout - общее время выполнения
  • WaitTimeout - время начального ожидания первого сообщения
  • IdleTimeout - время ожидания последующих сообщений

Если достигнут какой-либо из таймеров, приложение должно полностью завершиться. У меня это работает ниже

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 Детская площадка

Я хочу сделать WaitTimeout необязательным, но не знаю, как к нему подойти. Если я окружу конструкцию waitTimer оператором if, он не будет работать, поскольку waitTimer не определен для оператора select ... Как я могу сделать условное ожидание WaitTimeout?

Я могу просто .Stop() таймер после его создания, но это кажется немного грязным ...

1 Ответ

1 голос
/ 24 апреля 2020

Вы можете объявить таймер ожидания и его канал вне оператора if и инициализировать их, только если необходим таймер ожидания. Если нет, канал может остаться нулевым значением - которое составляет nil - потому что прием от nil блоков каналов будет продолжаться вечно, поэтому этот case никогда не будет готов (подробнее см. Как не инициализируется Канал ведет себя? ).

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)

    // ...
    }
}

Тогда, конечно, вы можете сбросить таймер ожидания только, если он существует, это также необходимо проверить (и не забудьте стереть канал, если он вернется false):

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

Попробуйте на игровой площадке Go .

...