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


    今天看到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

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

  • 相关阅读:
    12 Source Code Profilers for C & C++
    HttpWebRequest的使用方法
    MSDN Windows 下载
    Qt 4.7 在VS2010环境下的编译
    [转].NET Logging Tools and Libraries
    硬盘崩溃之后
    .net core 下使用 logdashboard 日志面板
    工具收藏 年终工作总结必备工具之ppt利器
    Dapper 的应用和Dapper.Contrib 的方法封装(一)
    Dapper 的应用和Dapper.Contrib 的方法封装(二)
  • 原文地址:https://www.cnblogs.com/zhangqingping/p/4683390.html
Copyright © 2020-2023  润新知