feat(cache): remove redis caching and add force refresh mechanism
- Remove Redis-based caching logic from uidScoreStore and xcxApi. - Add force refresh support to uidScoreRequest in GroupingPrediction component. - Update server API /api/user/nowScores to accept force parameter. - Always show refresh button in GroupingPrediction regardless of data state. - Change default sort type in FavPlayersPage to SCORE_DOWN. - Clean up unused imports from server.ts. This change ensures user scores are always up-to-date by bypassing cache when needed, preventing issues with stale data during manual sync operations.
This commit is contained in:
parent
8be15d51b1
commit
191906192b
@ -30,9 +30,9 @@ enum OrderScore {
|
||||
|
||||
export const GroupingPrediction: React.FC<Props> = props => {
|
||||
const { uidScore } = useLoaderData<{ uidScore: Map<string, string>}>();
|
||||
const uidScoreRequest = useRequest(async () => {
|
||||
const uidScoreRequest = useRequest(async (force?: boolean) => {
|
||||
const uids = props.players?.map(player => player.uid).filter(Boolean);
|
||||
const data = await fetch(`/api/user/nowScores`, {
|
||||
const data = await fetch(`/api/user/nowScores?force=${force ? 'true' : 'false'}`, {
|
||||
method: "POST",
|
||||
body: JSON.stringify({ uids }),
|
||||
}).then(res => res.json()).catch(() => ({}));
|
||||
@ -86,7 +86,7 @@ export const GroupingPrediction: React.FC<Props> = props => {
|
||||
});
|
||||
}, [players, grouped, groupLen, maxPlayerSize]);
|
||||
const handleSyncUidScore = useCallback(() => {
|
||||
uidScoreRequest.runAsync();
|
||||
uidScoreRequest.runAsync(true);
|
||||
}, []);
|
||||
return (
|
||||
<>
|
||||
@ -115,7 +115,7 @@ export const GroupingPrediction: React.FC<Props> = props => {
|
||||
OrderScore.年度积分,
|
||||
]} />
|
||||
</Form.Item>
|
||||
<Form.Item hidden={uidScore.size > 0 || (uidScoreRequest.data?.size || 0) > 0}>
|
||||
<Form.Item>
|
||||
<Button loading={uidScoreRequest.loading} onClick={handleSyncUidScore} icon={<SyncOutlined />}>
|
||||
刷新当前积分
|
||||
</Button>
|
||||
|
||||
@ -242,7 +242,8 @@ const server = Bun.serve({
|
||||
"/api/user/nowScores": {
|
||||
async POST(req) {
|
||||
const { uids } = await req.json();
|
||||
const uidScore = await getUidScore(uids);
|
||||
const force = Boolean(new URL(req.url).searchParams.get('force') === 'true');
|
||||
const uidScore = await getUidScore(uids, force);
|
||||
return Response.json(uidScore);
|
||||
}
|
||||
},
|
||||
@ -250,7 +251,7 @@ const server = Bun.serve({
|
||||
async GET(req) {
|
||||
const uid = req.params.uid;
|
||||
if (uid === '0') return Response.json(null);
|
||||
const profile = await xcxApi.getAdvProfile(uid);
|
||||
const profile = await xcxApi.getAdvProfile(uid, true);
|
||||
return Response.json(profile);
|
||||
},
|
||||
},
|
||||
|
||||
@ -30,7 +30,7 @@ const StyledContainer = styled.div`
|
||||
`;
|
||||
export function FavePlayersPage() {
|
||||
const { favMap, unFav } = useFavPlayerStore(state => state);
|
||||
const [sortType, setSortType] = useState<SortType>(SortType.DEFAULT);
|
||||
const [sortType, setSortType] = useState<SortType>(SortType.SCORE_DOWN);
|
||||
const [showType, setShowType] = useState(ShowType.LOCAL);
|
||||
const headers = useAuthHeaders();
|
||||
const { autoSignIn } = useAutoLogin();
|
||||
@ -110,7 +110,7 @@ export function FavePlayersPage() {
|
||||
value={sortType}
|
||||
onChange={e => setSortType(e)}
|
||||
options={[
|
||||
SortType.DEFAULT,
|
||||
// SortType.DEFAULT,
|
||||
SortType.SCORE_UP,
|
||||
SortType.SCORE_DOWN,
|
||||
]}
|
||||
|
||||
@ -1,18 +1,8 @@
|
||||
import { redis, REDIS_CACHE_HOUR, xcxApi } from '../utils/server';
|
||||
import { xcxApi } from '../utils/server';
|
||||
|
||||
const getKey = (uid: string) => `my-kaiqiuwang:uid-score:${uid}`;
|
||||
|
||||
const TIMEOUT = 60 * 60 * REDIS_CACHE_HOUR; // 24h;
|
||||
|
||||
export const getUidScore = async (uids: string[]): Promise<Record<string, string>> => {
|
||||
export const getUidScore = async (uids: string[], force?: boolean): Promise<Record<string, string>> => {
|
||||
const jobs = uids.map(async uid => {
|
||||
const key = getKey(uid);
|
||||
const value = await redis.get(key);
|
||||
if (value) {
|
||||
return [uid, value];
|
||||
}
|
||||
const profile = await xcxApi.getAdvProfile(uid);
|
||||
await redis.setex(key, TIMEOUT, profile?.score ?? '');
|
||||
const profile = await xcxApi.getAdvProfile(uid, force);
|
||||
return [uid, profile?.score ?? ''];
|
||||
});
|
||||
return Object.fromEntries(await Promise.all(jobs));
|
||||
|
||||
@ -33,12 +33,12 @@ export class XCXAPI {
|
||||
return response.data as T;
|
||||
}
|
||||
|
||||
async getAdvProfile(uid: string): Promise<XCXProfile | null> {
|
||||
async getAdvProfile(uid: string, force?: boolean): Promise<XCXProfile | null> {
|
||||
const cacheProfile = await redis.get(`my-kaiqiuwang:profile:${uid}`);
|
||||
if (!cacheProfile) {
|
||||
if (!cacheProfile || force) {
|
||||
const url = `/api/User/adv_profile?uid=${uid}`;
|
||||
const profile = await this.#fetch<XCXProfile>(url);
|
||||
await redis.setex(`my-kaiqiuwang:profile:${uid}`, 60 * 10, JSON.stringify(profile));
|
||||
await redis.setex(`my-kaiqiuwang:profile:${uid}`, 60 * 60 * 24, JSON.stringify(profile));
|
||||
return profile;
|
||||
}
|
||||
return JSON.parse(cacheProfile);
|
||||
|
||||
@ -1,7 +1,5 @@
|
||||
import type { EventDetail, Player } from "../types";
|
||||
import * as cheerio from "cheerio";
|
||||
import { XCXAPI } from "../services/xcxApi";
|
||||
import { KAIQIU_BASE_URL, LOGTO_DOMAIN } from "./common";
|
||||
import { LOGTO_DOMAIN } from "./common";
|
||||
import { RedisClient } from "bun";
|
||||
import { createRemoteJWKSet, jwtVerify } from 'jose';
|
||||
import { LOGTO_RESOURCE } from "./constants";
|
||||
|
||||
Loading…
Reference in New Issue
Block a user