我正在实现一个集成第三方 API 的应用程序,该 API 每秒的点击次数有限制。我编写了我的适配器,直到我使用竞争条件检测器运行测试之前,我是一个快乐的人。
设计很简单,有一个:
计算其发出的请求的结构
每秒将此计数器重置为 0 的刻度
该结构上的私有函数将被阻塞,直到满足条件以允许对 API 进行额外的调用。
运行此测试用例效果非常好,直到您给它-race
标记为止。我相信数据争用是由滴答线程试图重置命中计数器和增加它的调用请求引起的......
我的设计是否糟糕,或者我应该忍受数据争用警报吗?
import (
"sync"
"testing"
"time"
)
var subject httpClientWrapper
func init() {
subject = httpClientWrapper{
hits: 0,
hitsSecond: 1,
}
// reset hits every second to 0
go func() {
tick := time.Tick(1 * time.Second)
for range tick {
subject.hits = 0
}
}()
}
type httpClientWrapper struct {
hits, hitsSecond int
}
var m sync.Mutex
func (c *httpClientWrapper) allowCall() {
m.Lock()
callAllowanceReached := c.hits >= c.hitsSecond
for callAllowanceReached {
// cool down for one second
time.Sleep(1 * time.Second)
callAllowanceReached = c.hits >= c.hitsSecond
}
c.hits = c.hits + 1
m.Unlock()
}
func TestItSleeps(t *testing.T) {
timeStart := time.Now()
var wg = sync.WaitGroup{}
for i := 0; i < 3; i++ {
wg.Add(1)
go func() {
subject.allowCall()
wg.Done()
}()
}
wg.Wait()
elapsedTime := time.Since(timeStart)
if elapsedTime < (1 * time.Second) {
t.Errorf("this test should not had been able to run in less than a second due to locks and cool down")
}
}
PIPIONE
相关分类