Консольное приложение для своевременного опроса с индикатором времени, которое отображается при нажатии Ctrl + C - PullRequest
0 голосов
/ 28 мая 2018

Я хотел бы собрать токен на своевременной основе.Токен также получил информацию о том, когда он истекает.Это должно продолжаться до тех пор, пока пользователь не введет Ctrl + C.

Я пытался сделать то же самое с

span := timeLeft(*expDate)
timer := time.NewTimer(span).C
ticker := time.NewTicker(time.Second * 5).C

, который также не работает (приложение зависает после обратного отсчета).Поэтому я решил попробовать с <- time.After(...)

Это мой код, который не работает.Вы увидите обратный отсчет, но он никогда не прерывается по истечении срока действия.

Это небольшая выдержка с логикой опроса для простоты в main.go:

func refreshToken() (time.Time, error) {
        //This should simulate a http request and returns the new target date for the next refresh
        time.Sleep(2 * time.Second)
        return time.Now().Add(10 * time.Second), nil
    }

func timeLeft(d time.Time) time.Duration {
    exactLeft := d.Sub(time.Now())
    floorSeconds := math.Floor(exactLeft.Seconds())
    return time.Duration(floorSeconds) * time.Second
}

func poller(expDate *time.Time) {
    exp := timeLeft(*expDate)

    done := make(chan bool)
    c := make(chan os.Signal, 1)
    signal.Notify(c, os.Interrupt)
    for {
        select {

        // print time left on the screen
        case <-time.After(3 * time.Second):
            go func() {
                fmt.Printf("\rNext Token refresh will be in: %v", timeLeft(*expDate))
            }()
        // mark as done when date is due
        case <-time.After(exp):
            fmt.Println("Refresh token now!")
            done <- true

        // exit app
        case <-c:
            os.Exit(0)
            break

        // exit function when done
        case <-done:
            break
        }

    }
}

func main() {

    var expiration time.Time
    expiration = time.Now().Add(10 * time.Second)
    // loop and refresh token as long as the app does not exit
    for {
        poller(&expiration)

        ex, err := refreshToken()
        expiration = ex
        if err != nil {
            panic(err)
        }

        fmt.Println("next round poller")
    }
}

Я тожене уверен, нужен ли мне готовый канал вообще?Что требуется для прослушивания двух таймеров и вызова себя, пока кто-нибудь не нажмет Ctrl + C?

1 Ответ

0 голосов
/ 29 мая 2018

Нашел решение.Хотя @ain был правильным с буферизованным готовым каналом, в коде это сейчас не требуется.Это работало без него.

Трюк имел timer вне цикла for и ticker внутри него.Причина в том, что time.After - это func, которые возвращают новый канал на каждой итерации.Этот шов идеально подходит для тикера, но не для timer.Со следующими изменениями это сработало =) ...

   func poller(expDate *time.Time) {
        exp := timeLeft(*expDate)
        timer := time.After(exp)

        fmt.Printf("Next Token refresh will be in: %v\n", exp)

        c := make(chan os.Signal, 1)
        signal.Notify(c, os.Interrupt)
        for {
            select {

            // print time left on the screen
            case <-time.After(3 * time.Second):
                go func() {
                    fmt.Printf("\r     ")
                    fmt.Printf("\r%v", timeLeft(*expDate))
                }()
            // mark as done when date is due
            case <-timer:
                fmt.Println("Refresh token now!")
                return

            // exit app
            case <-c:
                os.Exit(0)
                break

            }
        }
    }
...