golang 中的定时器(timer),更巧妙的处理timeout

zhangqingping · · 6423 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

今天看到kite项目中的一段代码,发现挺有意思的。

 

// generateToken returns a JWT token string. Please see the URL for details:
// http://tools.ietf.org/html/draft-ietf-oauth-json-web-token-13#section-4.1
func generateToken(aud, username, issuer, privateKey string) (string, error) {
    tokenCacheMu.Lock()
    defer tokenCacheMu.Unlock()

    uniqKey := aud + username + issuer // neglect privateKey, its always the same
    signed, ok := tokenCache[uniqKey]
    if ok {
        return signed, nil
    }

    tknID, err := uuid.NewV4()
    if err != nil {
        return "", errors.New("Server error: Cannot generate a token")
    }

    // Identifies the expiration time after which the JWT MUST NOT be accepted
    // for processing.
    ttl := TokenTTL

    // Implementers MAY provide for some small leeway, usually no more than
    // a few minutes, to account for clock skew.
    leeway := TokenLeeway

    tkn := jwt.New(jwt.GetSigningMethod("RS256"))
    tkn.Claims["iss"] = issuer                                       // Issuer
    tkn.Claims["sub"] = username                                     // Subject
    tkn.Claims["aud"] = aud                                          // Audience
    tkn.Claims["exp"] = time.Now().UTC().Add(ttl).Add(leeway).Unix() // Expiration Time
    tkn.Claims["nbf"] = time.Now().UTC().Add(-leeway).Unix()         // Not Before
    tkn.Claims["iat"] = time.Now().UTC().Unix()                      // Issued At
    tkn.Claims["jti"] = tknID.String()                               // JWT ID

    signed, err = tkn.SignedString([]byte(privateKey))
    if err != nil {
        return "", errors.New("Server error: Cannot generate a token")
    }

    // cache our token
    tokenCache[uniqKey] = signed

    // cache invalidation, because we cache the token in tokenCache we need to
    // invalidate it expiration time. This was handled usually within JWT, but
    // now we have to do it manually for our own cache.
    time.AfterFunc(TokenTTL-TokenLeeway, func() {
        tokenCacheMu.Lock()
        defer tokenCacheMu.Unlock()

        delete(tokenCache, uniqKey)
    })

    return signed, nil
}

这里的  time.AfterFunc 来做token的timeout处理,是我之前都不知道的。

我之前的做法,自己启动一个 单独的 goroutine,对所有的token做遍历,判断是否timeout,timout了就进行删除操作。

看到了这段代码,第一个感觉是很妙,第二个是如果用起来,会不会有啥副作用。

翻看源码:https://golang.org/src/time/sleep.go?h=AfterFunc#L116

// AfterFunc waits for the duration to elapse and then calls f
   114    // in its own goroutine. It returns a Timer that can
   115    // be used to cancel the call using its Stop method.
   116    func AfterFunc(d Duration, f func()) *Timer {
   117        t := &Timer{
   118            r: runtimeTimer{
   119                when: when(d),
   120                f:    goFunc,
   121                arg:  f,
   122            },
   123        }
   124        startTimer(&t.r)
   125        return t
   126    }

这里的startTimer 是用了系统自身的timer实现,只不过是golang在这里做了一层兼容各个平台的封装,应该是没有什么副作用啦。

14    // Interface to timers implemented in package runtime.
    15    // Must be in sync with ../runtime/runtime.h:/^struct.Timer$
    16    type runtimeTimer struct {
    17        i      int
    18        when   int64
    19        period int64
    20        f      func(interface{}, uintptr) // NOTE: must not be closure
    21        arg    interface{}
    22        seq    uintptr
    23    }
    24    
    25    // when is a helper function for setting the 'when' field of a runtimeTimer.
    26    // It returns what the time will be, in nanoseconds, Duration d in the future.
    27    // If d is negative, it is ignored.  If the returned value would be less than
    28    // zero because of an overflow, MaxInt64 is returned.
    29    func when(d Duration) int64 {
    30        if d <= 0 {
    31            return runtimeNano()
    32        }
    33        t := runtimeNano() + int64(d)
    34        if t < 0 {
    35            t = 1<<63 - 1 // math.MaxInt64
    36        }
    37        return t
    38    }
    39    
    40    func startTimer(*runtimeTimer)
    41    func stopTimer(*runtimeTimer) bool

 

不得不感慨,原生库还是有很多好东东的,需要自己慢慢发觉。

 


有疑问加站长微信联系(非本文作者)

本文来自:博客园

感谢作者:zhangqingping

查看原文:golang 中的定时器(timer),更巧妙的处理timeout

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:1006366459

6423 次点击  ∙  1 赞  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传