diff --git a/lib/resty/etcd/v3.lua b/lib/resty/etcd/v3.lua index e1117caf..46dead37 100644 --- a/lib/resty/etcd/v3.lua +++ b/lib/resty/etcd/v3.lua @@ -19,6 +19,7 @@ local decode_json = cjson.decode local encode_json = cjson.encode local encode_base64 = ngx.encode_base64 local decode_base64 = ngx.decode_base64 +local semaphore = require("ngx.semaphore") local INIT_COUNT_RESIZE = 2e8 local _M = {} @@ -29,6 +30,7 @@ local mt = { __index = _M } local refresh_jwt_token local function _request_uri(self, method, uri, opts, timeout, ignore_auth) + utils.log_info("v3 request uri: ", uri, ", timeout: ", timeout) local body if opts and opts.body and tab_nkeys(opts.body) > 0 then @@ -162,8 +164,15 @@ function _M.new(opts) }) end + local sema, err = semaphore.new() + if not sema then + return nil, err + end + return setmetatable({ last_auth_time = now(), -- save last Authentication time + last_refresh_jwt_err = nil, + sema = sema, jwt_token = nil, -- last Authentication token is_auth = not not (user and password), user = user, @@ -195,6 +204,15 @@ local function choose_endpoint(self) return endpoints[pos] end + +local function wake_up_everyone(self) + local count = -self.sema:count() + if count > 0 then + self.sema:post(count) + end +end + + -- return refresh_is_ok, error function refresh_jwt_token(self) -- token exist and not expire @@ -204,6 +222,21 @@ function refresh_jwt_token(self) return true, nil end + if self.requesting_token then + self.sema:wait(5) + if self.jwt_token and now() - self.last_auth_time < 60 * 3 then + return true, nil + end + + if self.last_refresh_jwt_err then + utils.log_info("v3 refresh jwt last err: ", self.last_refresh_jwt_err) + return nil, self.last_refresh_jwt_err + end + end + + self.last_refresh_jwt_err = nil + self.requesting_token = true + local opts = { body = { name = self.user, @@ -213,16 +246,24 @@ function refresh_jwt_token(self) local res, err = _request_uri(self, 'POST', choose_endpoint(self).full_prefix .. "/auth/authenticate", opts, 5, true) -- default authenticate timeout 5 second + self.requesting_token = false + if err then + self.last_refresh_jwt_err = err + wake_up_everyone(self) return nil, err end if not res or not res.body or not res.body.token then - return nil, 'authenticate refresh token fail' + local err = 'authenticate refresh token fail' + self.last_refresh_jwt_err = err + wake_up_everyone(self) + return nil, err end self.jwt_token = res.body.token self.last_auth_time = now() + wake_up_everyone(self) return true, nil end