Implement stale entry cleanup in FreebitOperationsService to prevent memory leaks
- Added a method to periodically clean up stale operation timestamps, ensuring efficient memory usage. - Introduced rate limiting for cleanup operations to minimize performance overhead. - Enhanced the getOperationWindow method to invoke cleanup, maintaining optimal state of operation timestamps. - Included validation to ensure at least one feature is specified during updates, improving error handling.
This commit is contained in:
parent
b7f6c204e2
commit
e228f9342f
@ -55,7 +55,51 @@ export class FreebitOperationsService {
|
|||||||
}
|
}
|
||||||
>();
|
>();
|
||||||
|
|
||||||
|
// Rate limit cleanup to avoid running on every operation
|
||||||
|
private lastCleanupTime = 0;
|
||||||
|
private readonly cleanupIntervalMs = 5 * 60 * 1000; // Run cleanup at most every 5 minutes
|
||||||
|
private readonly staleThresholdMs = 35 * 60 * 1000; // Remove entries older than 35 minutes (beyond 30-min window)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cleanup stale entries from operationTimestamps to prevent memory leak.
|
||||||
|
* Entries are considered stale when all their timestamps are older than staleThresholdMs.
|
||||||
|
*/
|
||||||
|
private cleanupStaleEntries(): void {
|
||||||
|
const now = Date.now();
|
||||||
|
|
||||||
|
// Rate limit cleanup to avoid performance overhead
|
||||||
|
if (now - this.lastCleanupTime < this.cleanupIntervalMs) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.lastCleanupTime = now;
|
||||||
|
|
||||||
|
const staleThreshold = now - this.staleThresholdMs;
|
||||||
|
const accountsToRemove: string[] = [];
|
||||||
|
|
||||||
|
for (const [account, entry] of this.operationTimestamps) {
|
||||||
|
const timestamps = [entry.voice, entry.network, entry.plan, entry.cancellation].filter(
|
||||||
|
(t): t is number => typeof t === "number"
|
||||||
|
);
|
||||||
|
|
||||||
|
// If all timestamps are stale (or entry is empty), mark for removal
|
||||||
|
if (timestamps.length === 0 || timestamps.every(t => t < staleThreshold)) {
|
||||||
|
accountsToRemove.push(account);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const account of accountsToRemove) {
|
||||||
|
this.operationTimestamps.delete(account);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (accountsToRemove.length > 0) {
|
||||||
|
this.logger.debug(`Cleaned up ${accountsToRemove.length} stale operation timestamp entries`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private getOperationWindow(account: string) {
|
private getOperationWindow(account: string) {
|
||||||
|
// Run cleanup periodically to prevent memory leak
|
||||||
|
this.cleanupStaleEntries();
|
||||||
|
|
||||||
if (!this.operationTimestamps.has(account)) {
|
if (!this.operationTimestamps.has(account)) {
|
||||||
this.operationTimestamps.set(account, {});
|
this.operationTimestamps.set(account, {});
|
||||||
}
|
}
|
||||||
@ -457,6 +501,14 @@ export class FreebitOperationsService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Validate that at least one feature is specified
|
||||||
|
if (!hasVoiceFeatures && !hasNetworkTypeChange) {
|
||||||
|
throw new BadRequestException(
|
||||||
|
"No features specified for update. Please provide at least one of: " +
|
||||||
|
"voiceMailEnabled, callWaitingEnabled, internationalRoamingEnabled, or networkType."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (hasVoiceFeatures) {
|
if (hasVoiceFeatures) {
|
||||||
// Only voice features (PA05-06)
|
// Only voice features (PA05-06)
|
||||||
await this.updateVoiceFeatures(account, voiceFeatures);
|
await this.updateVoiceFeatures(account, voiceFeatures);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user