dongzhiyan5693 2018-05-28 10:18
浏览 52
已采纳

及时轮询控制台应用程序,其时间指示器在ctrl + c上退出

I would like to pool for a token in on a timely base. The Token itself got also information about when it expires. This should run forever until the user enters ctrl+c.

I tried the same with

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

which also does not work (the application hangs after count down). So I decided to try it with <- time.After(...)

This is my code that does not work. You will see the count down but it never breaks on expiration.

This is is a small extract with the polling logic for simplicity sake in a 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("Next 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")
    }
}

I am also not sure if I need the done channel at all? What is required to listen to two timers and call itself until someone hits ctrl+c?

  • 写回答

1条回答 默认 最新

  • dongsi2317 2018-05-29 05:10
    关注

    Found a solution. While @ain was right wit the buffered done channel, it is not really required in the code now. It worked without it.

    The trick did have the timeroutside of the for loop and the ticker within it. Reason is the time.Afteris a functhat return a new channel on every iteration. This seams perfectly fine for the ticker, but not for the timer. With the following changes it worked =) ...

       func poller(expDate *time.Time) {
            exp := timeLeft(*expDate)
            timer := time.After(exp)
    
            fmt.Printf("Next Token refresh will be in: %v
    ", 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("     ")
                        fmt.Printf("%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
    
                }
            }
        }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 数据库原理及应用上机练习题
  • ¥30 征集Python提取PDF文字属性的代码
  • ¥15 如何联系真正的开发者而非公司
  • ¥15 有偿求苍穹外卖环境配置
  • ¥15 代码在keil5里变成了这样怎么办啊,文件图像也变了,
  • ¥20 Ue4.26打包win64bit报错,如何解决?(语言-c++)
  • ¥15 clousx6整点报时指令怎么写
  • ¥30 远程帮我安装软件及库文件
  • ¥15 关于#自动化#的问题:如何通过电脑控制多相机同步拍照或摄影(相机或者摄影模组数量大于60),并将所有采集的照片或视频以一定编码规则存放至规定电脑文件夹内
  • ¥20 深信服vpn-2050这台设备如何配置才能成功联网?