fix: api /super-admin/{id} memory cache
This commit is contained in:
parent
7c70229579
commit
1a324af483
5 changed files with 112 additions and 2 deletions
158
src/utils/LogMemoryStore.ts
Normal file
158
src/utils/LogMemoryStore.ts
Normal file
|
|
@ -0,0 +1,158 @@
|
|||
import { AppDataSource } from "../database/data-source";
|
||||
import { OrgRevision } from "../entities/OrgRevision";
|
||||
import { Profile } from "../entities/Profile";
|
||||
import { PosMaster } from "../entities/PosMaster";
|
||||
|
||||
interface LogCacheData {
|
||||
currentRevision: OrgRevision | null;
|
||||
profileCache: Map<string, Profile>; // keycloak → Profile
|
||||
rootIdCache: Map<string, string>; // profileId → rootId
|
||||
updatedAt: Date;
|
||||
}
|
||||
|
||||
class LogMemoryStore {
|
||||
private cache: LogCacheData = {
|
||||
currentRevision: null,
|
||||
profileCache: new Map(),
|
||||
rootIdCache: new Map(),
|
||||
updatedAt: new Date(),
|
||||
};
|
||||
private readonly REFRESH_INTERVAL = 10 * 60 * 1000; // 10 minutes
|
||||
private isRefreshing = false;
|
||||
private isInitialized = false;
|
||||
private refreshTimer: NodeJS.Timeout | null = null;
|
||||
|
||||
constructor() {
|
||||
// ไม่ refresh ทันที - รอให้เรียก initialize() หลัง TypeORM ready
|
||||
}
|
||||
|
||||
// เริ่มต้น cache หลังจาก TypeORM initialize เสร็จ
|
||||
initialize() {
|
||||
if (this.isInitialized) {
|
||||
console.log("[LogMemoryStore] Already initialized");
|
||||
return;
|
||||
}
|
||||
|
||||
this.isInitialized = true;
|
||||
this.refreshCache();
|
||||
this.refreshTimer = setInterval(() => {
|
||||
this.refreshCache();
|
||||
}, this.REFRESH_INTERVAL);
|
||||
|
||||
console.log(
|
||||
"[LogMemoryStore] Initialized with",
|
||||
this.REFRESH_INTERVAL / 1000,
|
||||
"second refresh interval",
|
||||
);
|
||||
}
|
||||
|
||||
private async refreshCache() {
|
||||
if (this.isRefreshing) {
|
||||
console.log("[LogMemoryStore] Already refreshing, skipping...");
|
||||
return;
|
||||
}
|
||||
|
||||
this.isRefreshing = true;
|
||||
try {
|
||||
// Refresh revision cache
|
||||
const repoRevision = AppDataSource.getRepository(OrgRevision);
|
||||
const revision = await repoRevision.findOne({
|
||||
where: {
|
||||
orgRevisionIsCurrent: true,
|
||||
orgRevisionIsDraft: false,
|
||||
},
|
||||
});
|
||||
this.cache.currentRevision = revision;
|
||||
|
||||
// Clear on-demand caches (they will be rebuilt as needed)
|
||||
this.cache.profileCache.clear();
|
||||
this.cache.rootIdCache.clear();
|
||||
|
||||
this.cache.updatedAt = new Date();
|
||||
console.log("[LogMemoryStore] Cache refreshed at", this.cache.updatedAt.toISOString());
|
||||
} catch (error) {
|
||||
console.error("[LogMemoryStore] Error refreshing cache:", error);
|
||||
} finally {
|
||||
this.isRefreshing = false;
|
||||
}
|
||||
}
|
||||
|
||||
getCurrentRevision(): OrgRevision | null {
|
||||
return this.cache.currentRevision;
|
||||
}
|
||||
|
||||
getLastUpdateTime(): Date {
|
||||
return this.cache.updatedAt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Profile by keycloak ID with caching
|
||||
*/
|
||||
async getProfileByKeycloak(keycloak: string): Promise<Profile | null> {
|
||||
// Check cache first
|
||||
if (this.cache.profileCache.has(keycloak)) {
|
||||
return this.cache.profileCache.get(keycloak)!;
|
||||
}
|
||||
|
||||
// Fetch from database
|
||||
const repoProfile = AppDataSource.getRepository(Profile);
|
||||
const profile = await repoProfile.findOne({
|
||||
where: { keycloak },
|
||||
});
|
||||
|
||||
// Cache the result
|
||||
if (profile) {
|
||||
this.cache.profileCache.set(keycloak, profile);
|
||||
}
|
||||
|
||||
return profile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get RootId by profileId with caching
|
||||
*/
|
||||
async getRootIdByProfileId(profileId: string | undefined): Promise<string | null> {
|
||||
if (!profileId) return null;
|
||||
|
||||
// Check cache first
|
||||
if (this.cache.rootIdCache.has(profileId)) {
|
||||
return this.cache.rootIdCache.get(profileId)!;
|
||||
}
|
||||
|
||||
// Fetch from database
|
||||
const repoPosmaster = AppDataSource.getRepository(PosMaster);
|
||||
const revision = this.getCurrentRevision();
|
||||
//
|
||||
const posMaster = await repoPosmaster.findOne({
|
||||
where: {
|
||||
current_holderId: profileId,
|
||||
orgRevisionId: revision?.id,
|
||||
},
|
||||
relations: ["orgRoot"],
|
||||
select: {
|
||||
orgRoot: {
|
||||
ancestorDNA: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const rootId = posMaster?.orgRoot?.ancestorDNA ?? null;
|
||||
|
||||
// Cache the result
|
||||
if (rootId) {
|
||||
this.cache.rootIdCache.set(profileId, rootId);
|
||||
}
|
||||
|
||||
return rootId;
|
||||
}
|
||||
|
||||
// สำหรับ shutdown
|
||||
destroy() {
|
||||
if (this.refreshTimer) {
|
||||
clearInterval(this.refreshTimer);
|
||||
this.refreshTimer = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const logMemoryStore = new LogMemoryStore();
|
||||
Loading…
Add table
Add a link
Reference in a new issue