所以我希望能够有一个通用的函数来获取令牌,在我所有的传奇命中一个特定的API。这就是我想出来的
function* getValidAuthToken(params: TokenParams) {
// Refresh token 5 seconds before actual expiration. This gives some buffer time
// for inflight requests to succeed
const bufferTimeMS = 10000;
const token = yield select(tokenSelector);
if (token && Date.now() < token.tokenExpirationTimeStampMs - bufferTimeMS) {
return token.tokenValue;
}
const isUpdating = yield select(isCurrUpdatingToken);
// If another saga has already started the process to fetch a new token we just wait for that to finish
if (isUpdating) {
yield take(finishTokenUpdate);
const token = yield select(tokenSelector);
return token.tokenValue;
}
// Else we start the process to get a new lrs token
yield put(startTokenUpdate());
const result = yield sdk.getToken(params);
const { tokenValue, lifetimeSeconds } = result.token;
const tokenExpirationTimeStamp = Date.now() + lifetimeSeconds * 1000;
yield put(finishTokenUpdate({ tokenExpirationTimeStampMs: tokenExpirationTimeStamp, tokenValue }));
return tokenValue;
}
我包含了一个状态isUpdating
,以避免在另一个消费者已经启动该流程的情况下获取令牌。在这种情况下,我只想等待令牌更新完成,并获取结果。
然而,我注意到的是,在应用程序启动…多个消费者同时调用我的服务。在这种情况下,isUpdating
标志没有时间改变,实际上它是一个比赛条件,无论getToken
是否被多次调用。
好吧,实际上我觉得自己很蠢....在我发布这篇文章的那一刻,我发现了我的错误。
我的reducer是这样写的
import { finishTokenUpdate, startTokenUpdate } from './actions';
const isUpdatingTokenHanlder = handleActions(
{
startTokenupdate: (state, action) => true,
finishTokenUpdate: (state, action) => false,
},
false,
);
这没有正确定义我的操作键。而应该是
const isUpdatingTokenHanlder = handleActions(
{
[`${startTokenUpdate}`]: (state, action) => true,
....
);