refactor: Optimize message cache initialization and retrieval logic
- Simplify message cache initialization in server hooks - Streamline message fetching for public and private chat rooms - Improve cache usage and fallback mechanisms - Remove redundant cache checks and add more focused logging
- commit
- 3975fb4bb6c8993707c97bb0607b6c831a1f55d5
- author
- Kit · · 2025-02-14 14:30 UTC
- parent
- a665266
- signature
- SSH Unverified
SHA256:H91DFuEG4jpk5edzLA4aUKkpv4zv9Q339ipRmkph6TkThe key is unknown
3 files · +44 -28
M src/hooks.server.ts +2 -0
| @@ -5,6 +5,7 @@ import { initializeDatabase } from "$lib/db/db.server"; | |||
| 5 | 5 | import db from "$lib/db/db.server"; | |
| 6 | 6 | import { handleRateLimit } from "$lib/api/rate-limiter"; | |
| 7 | 7 | import { users } from "$lib/db/schema"; | |
| 8 | + | import { initializeMessageCache } from "$lib/cache/initialize-cache"; | |
| 8 | 9 | ||
| 9 | 10 | async function setAllUsersOffline() { | |
| 10 | 11 | try { | |
| @@ -24,6 +25,7 @@ console.debug("Initializing database on server start..."); | |||
| 24 | 25 | initializeDatabase() | |
| 25 | 26 | .then(async () => { | |
| 26 | 27 | await setAllUsersOffline(); | |
| 28 | + | await initializeMessageCache(); | |
| 27 | 29 | }) | |
| 28 | 30 | .catch(error => { | |
| 29 | 31 | console.error('Failed to initialize database:', error); | |
| @@ -5,6 +5,7 @@ import { initializeDatabase } from "$lib/db/db.server"; | |||||
| 5 | import db from "$lib/db/db.server"; | 5 | import db from "$lib/db/db.server"; | ||
| 6 | import { handleRateLimit } from "$lib/api/rate-limiter"; | 6 | import { handleRateLimit } from "$lib/api/rate-limiter"; | ||
| 7 | import { users } from "$lib/db/schema"; | 7 | import { users } from "$lib/db/schema"; | ||
| 8 | + | import { initializeMessageCache } from "$lib/cache/initialize-cache"; | |||
| 8 | 9 | ||||
| 9 | async function setAllUsersOffline() { | 10 | async function setAllUsersOffline() { | ||
| 10 | try { | 11 | try { | ||
| @@ -24,6 +25,7 @@ console.debug("Initializing database on server start..."); | |||||
| 24 | initializeDatabase() | 25 | initializeDatabase() | ||
| 25 | .then(async () => { | 26 | .then(async () => { | ||
| 26 | await setAllUsersOffline(); | 27 | await setAllUsersOffline(); | ||
| 28 | + | await initializeMessageCache(); | |||
| 27 | }) | 29 | }) | ||
| 28 | .catch(error => { | 30 | .catch(error => { | ||
| 29 | console.error('Failed to initialize database:', error); | 31 | console.error('Failed to initialize database:', error); | ||
A src/lib/cache/initialize-cache.ts +30 -0
| @@ -0,0 +1,30 @@ | |||
| 1 | + | import { messageCache } from '$lib/cache/message-cache'; | |
| 2 | + | import db from '$lib/db/db.server'; | |
| 3 | + | import { messages } from '$lib/db/schema'; | |
| 4 | + | import { desc } from 'drizzle-orm'; | |
| 5 | + | ||
| 6 | + | let isCacheInitialized = false; | |
| 7 | + | ||
| 8 | + | export async function initializeMessageCache(): Promise<void> { | |
| 9 | + | if (isCacheInitialized) { | |
| 10 | + | console.debug('[Cache] Message cache already initialized.'); | |
| 11 | + | return; | |
| 12 | + | } | |
| 13 | + | try { | |
| 14 | + | console.debug('[Cache] Initializing message cache with pre-population.'); | |
| 15 | + | const fetchedMessages = await db.select() | |
| 16 | + | .from(messages) | |
| 17 | + | .orderBy(desc(messages.timestamp)) | |
| 18 | + | .limit(500); | |
| 19 | + | // Reverse to get messages in chronological order | |
| 20 | + | await messageCache.initialize(fetchedMessages.reverse()); | |
| 21 | + | isCacheInitialized = true; | |
| 22 | + | const stats = messageCache.getCacheStats(); | |
| 23 | + | console.debug('[Cache] Message cache initialized successfully:', { | |
| 24 | + | roomCount: stats.roomCount, | |
| 25 | + | totalMessages: stats.totalMessages | |
| 26 | + | }); | |
| 27 | + | } catch (error) { | |
| 28 | + | console.error('[Cache] Failed to initialize message cache:', error); | |
| 29 | + | } | |
| 30 | + | } ⏎̸ | |
| @@ -0,0 +1,30 @@ | |||||
| 1 | + | import { messageCache } from '$lib/cache/message-cache'; | |||
| 2 | + | import db from '$lib/db/db.server'; | |||
| 3 | + | import { messages } from '$lib/db/schema'; | |||
| 4 | + | import { desc } from 'drizzle-orm'; | |||
| 5 | + | ||||
| 6 | + | let isCacheInitialized = false; | |||
| 7 | + | ||||
| 8 | + | export async function initializeMessageCache(): Promise<void> { | |||
| 9 | + | if (isCacheInitialized) { | |||
| 10 | + | console.debug('[Cache] Message cache already initialized.'); | |||
| 11 | + | return; | |||
| 12 | + | } | |||
| 13 | + | try { | |||
| 14 | + | console.debug('[Cache] Initializing message cache with pre-population.'); | |||
| 15 | + | const fetchedMessages = await db.select() | |||
| 16 | + | .from(messages) | |||
| 17 | + | .orderBy(desc(messages.timestamp)) | |||
| 18 | + | .limit(500); | |||
| 19 | + | // Reverse to get messages in chronological order | |||
| 20 | + | await messageCache.initialize(fetchedMessages.reverse()); | |||
| 21 | + | isCacheInitialized = true; | |||
| 22 | + | const stats = messageCache.getCacheStats(); | |||
| 23 | + | console.debug('[Cache] Message cache initialized successfully:', { | |||
| 24 | + | roomCount: stats.roomCount, | |||
| 25 | + | totalMessages: stats.totalMessages | |||
| 26 | + | }); | |||
| 27 | + | } catch (error) { | |||
| 28 | + | console.error('[Cache] Failed to initialize message cache:', error); | |||
| 29 | + | } | |||
| 30 | + | } ⏎̸ | |||
M src/routes/api/chat/messages/+server.ts +12 -28
| @@ -89,34 +89,23 @@ export async function GET({ request, locals }) { | |||
| 89 | 89 | // Ensure default chat room exists | |
| 90 | 90 | await ensureDefaultChatRoom(db); | |
| 91 | 91 | ||
| 92 | - | // Initialize cache if needed | |
| 93 | - | if (!isCacheInitialized) { | |
| 94 | - | await initializeCache(); | |
| 95 | - | } | |
| 96 | - | ||
| 97 | - | console.log('[Chat] Fetching messages', { | |
| 98 | - | isPublic, | |
| 99 | - | fromCache: isCacheInitialized, | |
| 100 | - | roomId | |
| 101 | - | }); | |
| 102 | - | ||
| 103 | 92 | let fetchedMessages: Message[]; | |
| 104 | - | if (isCacheInitialized) { | |
| 105 | - | // Get from cache | |
| 106 | - | fetchedMessages = messageCache.getMessages(roomId, isPublic ? 10 : 50); | |
| 93 | + | if (isPublic) { | |
| 94 | + | if (!isCacheInitialized) { | |
| 95 | + | await initializeCache(); | |
| 96 | + | } | |
| 97 | + | console.log('[Chat] Fetching public messages from cache', { roomId }); | |
| 98 | + | fetchedMessages = messageCache.getMessages(roomId, 10); | |
| 107 | 99 | } else { | |
| 108 | - | // Fallback to DB if cache initialization failed | |
| 100 | + | if (!locals.user) { | |
| 101 | + | throw error(401, 'Authentication required'); | |
| 102 | + | } | |
| 103 | + | console.log('[Chat] Fetching messages from DB for instant chat', { roomId }); | |
| 109 | 104 | const query = db.select() | |
| 110 | 105 | .from(messages) | |
| 111 | 106 | .where(eq(messages.chatRoomId, roomId)) | |
| 112 | - | .orderBy(desc(messages.timestamp)); | |
| 113 | - | ||
| 114 | - | if (isPublic) { | |
| 115 | - | query.limit(10); | |
| 116 | - | } else { | |
| 117 | - | query.limit(50); | |
| 118 | - | } | |
| 119 | - | ||
| 107 | + | .orderBy(desc(messages.timestamp)) | |
| 108 | + | .limit(50); | |
| 120 | 109 | fetchedMessages = (await query).reverse(); | |
| 121 | 110 | } | |
| 122 | 111 | ||
| @@ -245,11 +234,6 @@ export async function POST({ request, locals }: { request: Request, locals: App. | |||
| 245 | 234 | timestamp: newMessage.timestamp | |
| 246 | 235 | }); | |
| 247 | 236 | ||
| 248 | - | // Add to cache if initialized | |
| 249 | - | if (isCacheInitialized) { | |
| 250 | - | messageCache.addMessage(newMessage); | |
| 251 | - | } | |
| 252 | - | ||
| 253 | 237 | // Broadcast the new message via the unified SSE emitter | |
| 254 | 238 | sseEmitter.emit('sse', { type: 'chatMessage', data: newMessage }); | |
| 255 | 239 | ||
| @@ -89,34 +89,23 @@ export async function GET({ request, locals }) { | |||||
| 89 | // Ensure default chat room exists | 89 | // Ensure default chat room exists | ||
| 90 | await ensureDefaultChatRoom(db); | 90 | await ensureDefaultChatRoom(db); | ||
| 91 | 91 | ||||
| 92 | - | // Initialize cache if needed | |||
| 93 | - | if (!isCacheInitialized) { | |||
| 94 | - | await initializeCache(); | |||
| 95 | - | } | |||
| 96 | - | ||||
| 97 | - | console.log('[Chat] Fetching messages', { | |||
| 98 | - | isPublic, | |||
| 99 | - | fromCache: isCacheInitialized, | |||
| 100 | - | roomId | |||
| 101 | - | }); | |||
| 102 | - | ||||
| 103 | let fetchedMessages: Message[]; | 92 | let fetchedMessages: Message[]; | ||
| 104 | - | if (isCacheInitialized) { | 93 | + | if (isPublic) { |
| 105 | - | // Get from cache | 94 | + | if (!isCacheInitialized) { |
| 106 | - | fetchedMessages = messageCache.getMessages(roomId, isPublic ? 10 : 50); | 95 | + | await initializeCache(); |
| 96 | + | } | |||
| 97 | + | console.log('[Chat] Fetching public messages from cache', { roomId }); | |||
| 98 | + | fetchedMessages = messageCache.getMessages(roomId, 10); | |||
| 107 | } else { | 99 | } else { | ||
| 108 | - | // Fallback to DB if cache initialization failed | 100 | + | if (!locals.user) { |
| 101 | + | throw error(401, 'Authentication required'); | |||
| 102 | + | } | |||
| 103 | + | console.log('[Chat] Fetching messages from DB for instant chat', { roomId }); | |||
| 109 | const query = db.select() | 104 | const query = db.select() | ||
| 110 | .from(messages) | 105 | .from(messages) | ||
| 111 | .where(eq(messages.chatRoomId, roomId)) | 106 | .where(eq(messages.chatRoomId, roomId)) | ||
| 112 | - | .orderBy(desc(messages.timestamp)); | 107 | + | .orderBy(desc(messages.timestamp)) |
| 113 | - | 108 | + | .limit(50); | |
| 114 | - | if (isPublic) { | |||
| 115 | - | query.limit(10); | |||
| 116 | - | } else { | |||
| 117 | - | query.limit(50); | |||
| 118 | - | } | |||
| 119 | - | ||||
| 120 | fetchedMessages = (await query).reverse(); | 109 | fetchedMessages = (await query).reverse(); | ||
| 121 | } | 110 | } | ||
| 122 | 111 | ||||
| @@ -245,11 +234,6 @@ export async function POST({ request, locals }: { request: Request, locals: App. | |||||
| 245 | timestamp: newMessage.timestamp | 234 | timestamp: newMessage.timestamp | ||
| 246 | }); | 235 | }); | ||
| 247 | 236 | ||||
| 248 | - | // Add to cache if initialized | |||
| 249 | - | if (isCacheInitialized) { | |||
| 250 | - | messageCache.addMessage(newMessage); | |||
| 251 | - | } | |||
| 252 | - | ||||
| 253 | // Broadcast the new message via the unified SSE emitter | 237 | // Broadcast the new message via the unified SSE emitter | ||
| 254 | sseEmitter.emit('sse', { type: 'chatMessage', data: newMessage }); | 238 | sseEmitter.emit('sse', { type: 'chatMessage', data: newMessage }); | ||
| 255 | 239 | ||||