Using Ticker for polling an API in Go

huangapple go评论63阅读模式
英文:

Using Ticker for polling an API in Go

问题

有一个API我需要定期轮询,以检查状态消息。

ticker := time.NewTicker(time.Second * tickerWaitTimeSeconds)
defer ticker.Stop()

for range ticker.C {
    res, err := r.client.Get(someURL)
    if err != nil {
        results <- err
        return
    }
    if err := json.NewDecoder(res.Body).Decode(&response); err != nil {
        results <- err
        return
    }
    status := response.Data.Attributes.CompleteStatus
    if status == "COMPLETED" {
        results <- nil
        return
    }
    if status == "ERROR" {
        results <- ErrFailedJob
        return
    }
}

到目前为止,它一直以相当稳定的方式工作,但是如果我正确理解了ticker的工作原理,可能会有一个潜在的问题。

有一个名为tickerWaitTimeSeconds的常量,目前设置为2秒。选择这个值是为了确保请求有足够的时间成功(它甚至不接近1秒,更不用说2秒了),并且我们不会对API进行过多的请求。

然而,我怀疑,如果由于某种原因请求的时间超过了tickerWaitTimeSeconds,可能会有比必要更多的GET请求发送到API。

在这种情况下,我的怀疑是否正确?也许,我对实际发生的情况有些误解,Get调用会阻塞ticker,但我怀疑这是否是真的。

英文:

There is an API that I need to periodically poll in order to check the status message.

ticker := time.NewTicker(time.Second * tickerWaitTimeSeconds)
defer ticker.Stop()

for range ticker.C {
		res, err := r.client.Get(someURL)
		if err != nil {
			results &lt;- err
			return
		}
		if err := json.NewDecoder(res.Body).Decode(&amp;response); err != nil {
			results &lt;- err
			return
		}
		status := response.Data.Attributes.CompleteStatus
		if status == &quot;COMPLETED&quot; {
			results &lt;- nil
			return
		}
		if status == &quot;ERROR&quot; {
			results &lt;- ErrFailedJob
			return
		}

It has worked in quite a stable way so far, but there is one possible catch if I understand how tickers work correctly.

There is this constant tickerWaitTimeSeconds that is currently set to 2 seconds. The value was chosen in such a way that the request has enough time to succeed (it's not even close to 1 second, not to mention 2) and we don't spam the API.

I suspect, however, that if for some reason the request takes longer than tickerWaitTimeSeconds there might be more GET requests to the API than necessary.

Is my suspicion valid in this case? Probably, there is something wrong with my understanding of what really happens and the Get call blocks the ticker, but I doubt that's the case.

答案1

得分: 1

根据文档的说明:

Ticker会调整时间间隔或丢弃ticks来弥补慢接收器。

因此,如果Get方法的执行时间超过tick间隔,Ticker会丢弃ticks。Get方法不在单独的goroutine中运行,因此在任何给定时间内不能同时提交多个请求。可能的情况是,如果一个Get方法持续3秒,下一个Get方法会在第一个方法之后1秒发生。如果你想在上一次调用完成后至少2秒后调用API,请在每次迭代时重置Ticker。

英文:

Based on the ticker documentation:

> The ticker will adjust the time interval or drop ticks to make up for slow receivers.

So the ticker should drop ticks if Get takes longer than tick interval. The Get call is not run in a separate goroutine, so you cannot submit more than one request at any given time. It may be that if one Get lasts 3 seconds, the next Get happens 1 second after the first one. If you want to call the API at least 2 seconds after the completion of the previous call, reset the ticker at each iteration.

答案2

得分: 1

为什么需要使用ticker?使用time.Sleep()不是更简单吗?

类似这样的代码:

import (
	"fmt"
	"time"
)

func ticktock(d time.Duration) {

	for true {
		doSomethingUseful()
		time.Sleep(d)
	}
}

在https://go.dev/play/p/xtg6bqNdwuk 上可以看到它的运行效果。

你可能想要跟踪执行doSomethingUseful()所需的经过时间,并从睡眠间隔中减去该时间,这样你就永远不会睡眠超过指定的持续时间,但可能会睡眠时间更短。

英文:

Why do you need a ticker? Wouldn't it be easier to use time.Sleep()?

Something like this:

import (
	&quot;fmt&quot;
	&quot;time&quot;
)

func ticktock( d time.Duration ) {

	for true {
		doSomethingUseful()
		time.Sleep(d)
	}
}

See it in action at https://go.dev/play/p/xtg6bqNdwuk

You might want to track the elapsed time required to doSomethingUseful() and deduct that from the sleep interval, so you'd never sleep more than the specified duration, but you might sleep less.

huangapple
  • 本文由 发表于 2022年1月21日 03:11:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/70792123.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定