zoukankan      html  css  js  c++  java
  • 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

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

  • 相关阅读:
    遗传算法(Genetic Algorithm, GA)及MATLAB实现
    CCF CSP 201809-2 买菜
    PAT (Basic Level) Practice (中文)1008 数组元素循环右移问题 (20 分)
    PAT (Basic Level) Practice (中文)1006 换个格式输出整数 (15 分)
    PAT (Basic Level) Practice (中文)1004 成绩排名 (20 分)
    PAT (Basic Level) Practice (中文)1002 写出这个数 (20 分)
    PAT (Advanced Level) Practice 1001 A+B Format (20 分)
    BP神经网络(原理及MATLAB实现)
    问题 1676: 算法2-8~2-11:链表的基本操作
    问题 1744: 畅通工程 (并查集)
  • 原文地址:https://www.cnblogs.com/zhangqingping/p/4683390.html
Copyright © 2011-2022 走看看