···
private analyticsCache: Map<string, { data: any; timestamp: number }> = new Map();
private analyticsCacheTTL = 30000; // 30 second cache for faster updates
52
+
// Background user update queue to avoid Slack API limits
53
+
private userUpdateQueue: Set<string> = new Set();
54
+
private isProcessingQueue = false;
55
+
private slackWrapper?: any; // Will be injected after construction
* Creates a new Cache instance
* @param dbPath Path to SQLite database file
···
this.setupPurgeSchedule();
74
+
this.startQueueProcessor();
···
331
+
* Sets the Slack wrapper for user updates
332
+
* @param slackWrapper SlackWrapper instance for API calls
334
+
setSlackWrapper(slackWrapper: any) {
335
+
this.slackWrapper = slackWrapper;
339
+
* Adds a user to the background update queue
340
+
* @param userId User ID to queue for update
343
+
private queueUserUpdate(userId: string) {
344
+
this.userUpdateQueue.add(userId.toUpperCase());
348
+
* Starts the background queue processor
351
+
private startQueueProcessor() {
352
+
// Process queue every 30 seconds to respect Slack API limits
353
+
setInterval(async () => {
354
+
await this.processUserUpdateQueue();
359
+
* Processes the user update queue with rate limiting
362
+
private async processUserUpdateQueue() {
363
+
if (this.isProcessingQueue || this.userUpdateQueue.size === 0 || !this.slackWrapper) {
367
+
this.isProcessingQueue = true;
370
+
// Process up to 3 users at a time to respect API limits
371
+
const usersToUpdate = Array.from(this.userUpdateQueue).slice(0, 3);
373
+
for (const userId of usersToUpdate) {
375
+
console.log(`Background updating user: ${userId}`);
376
+
const slackUser = await this.slackWrapper.getUserInfo(userId);
378
+
// Update user in cache with fresh data
379
+
await this.insertUser(
381
+
slackUser.real_name || slackUser.name || "Unknown",
382
+
slackUser.profile?.pronouns || "",
383
+
slackUser.profile?.image_512 || slackUser.profile?.image_192 || ""
386
+
// Remove from queue after successful update
387
+
this.userUpdateQueue.delete(userId);
389
+
console.warn(`Failed to update user ${userId}:`, error);
390
+
// Remove from queue even if failed to prevent infinite retry
391
+
this.userUpdateQueue.delete(userId);
395
+
console.error("Error processing user update queue:", error);
397
+
this.isProcessingQueue = false;
* Inserts a user into the cache
* @param userId Unique identifier for the user
* @param imageUrl URL of the user's image
···
483
-
if (new Date(result.expiration).getTime() < Date.now()) {
560
+
const now = Date.now();
561
+
const expiration = new Date(result.expiration).getTime();
563
+
// If user is expired, remove and return null
564
+
if (expiration < now) {
this.db.run("DELETE FROM users WHERE userId = ?", [userId]);
569
+
// Touch-to-refresh: if user is older than 24 hours, extend TTL and queue for background update
570
+
const twentyFourHoursAgo = now - (24 * 60 * 60 * 1000);
571
+
const userAge = expiration - (7 * 24 * 60 * 60 * 1000); // When user was originally cached
573
+
if (userAge < twentyFourHoursAgo) {
574
+
// Extend TTL by another 7 days from now
575
+
const newExpiration = now + (7 * 24 * 60 * 60 * 1000);
576
+
this.db.run("UPDATE users SET expiration = ? WHERE userId = ?", [
578
+
userId.toUpperCase()
581
+
// Queue for background update to get fresh data
582
+
this.queueUserUpdate(userId);
584
+
console.log(`Touch-refresh: Extended TTL for user ${userId} and queued for update`);