redis caching updated optimized loading and data readiness
This commit is contained in:
+66
-16
@@ -81,25 +81,52 @@ app.get('/api/jobs', async (c) => {
|
|||||||
// Fast endpoint: returns all jobs in a single cached request
|
// Fast endpoint: returns all jobs in a single cached request
|
||||||
app.get('/api/jobs-all', async (c) => {
|
app.get('/api/jobs-all', async (c) => {
|
||||||
const cacheKey = 'jobs:all';
|
const cacheKey = 'jobs:all';
|
||||||
const ttl = 300; // 5 minutes cache
|
const ttl = 1800; // 30 minutes cache
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Try to get from cache first
|
// Always try cache first for instant response
|
||||||
if (isRedisConnected()) {
|
if (isRedisConnected()) {
|
||||||
const cached = await getCache(cacheKey);
|
const cached = await getCache(cacheKey);
|
||||||
if (cached) {
|
if (cached) {
|
||||||
logLine('logs/server.log', `Cache HIT for ${cacheKey} (${cached.items?.length || 0} jobs)`);
|
logLine('logs/server.log', `Cache HIT for ${cacheKey} (${cached.items?.length || 0} jobs)`);
|
||||||
|
|
||||||
|
// Return cached data immediately, refresh in background if needed
|
||||||
|
setImmediate(async () => {
|
||||||
|
try {
|
||||||
|
await refreshJobsCache(cacheKey, ttl, c.req.header('Authorization') || '');
|
||||||
|
} catch (err) {
|
||||||
|
// Silently fail background refresh
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return c.json(cached);
|
return c.json(cached);
|
||||||
}
|
}
|
||||||
logLine('logs/server.log', `Cache MISS for ${cacheKey} - fetching all jobs`);
|
logLine('logs/server.log', `Cache MISS for ${cacheKey} - fetching all jobs`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const authHeader = c.req.header('Authorization') || '';
|
// No cache available, fetch now
|
||||||
|
const result = await fetchAllJobsFromPocketBase(c.req.header('Authorization') || '');
|
||||||
|
|
||||||
|
// Cache the result
|
||||||
|
if (isRedisConnected()) {
|
||||||
|
await setCache(cacheKey, result, ttl);
|
||||||
|
logLine('logs/server.log', `Cached ${cacheKey} with ${result.items.length} jobs for ${ttl}s`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.json(result);
|
||||||
|
|
||||||
|
} catch (err) {
|
||||||
|
logLine('logs/error.log', `jobs-all endpoint error: ${(err as Error)?.message || String(err)}`);
|
||||||
|
return c.json({ error: 'Failed to fetch jobs' }, 500);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Helper function to fetch all jobs from PocketBase
|
||||||
|
async function fetchAllJobsFromPocketBase(authHeader: string): Promise<any> {
|
||||||
const allItems: any[] = [];
|
const allItems: any[] = [];
|
||||||
let page = 1;
|
let page = 1;
|
||||||
const perPage = 500; // Large page size
|
const perPage = 500;
|
||||||
|
|
||||||
// Fetch all pages from PocketBase
|
|
||||||
while (true) {
|
while (true) {
|
||||||
const pbUrl = `https://pocketbase.ccllc.pro/api/collections/pbc_1407612689/records?page=${page}&perPage=${perPage}&sort=-Job_Number`;
|
const pbUrl = `https://pocketbase.ccllc.pro/api/collections/pbc_1407612689/records?page=${page}&perPage=${perPage}&sort=-Job_Number`;
|
||||||
const response = await fetch(pbUrl, {
|
const response = await fetch(pbUrl, {
|
||||||
@@ -120,27 +147,25 @@ app.get('/api/jobs-all', async (c) => {
|
|||||||
page++;
|
page++;
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = {
|
return {
|
||||||
page: 1,
|
page: 1,
|
||||||
perPage: allItems.length,
|
perPage: allItems.length,
|
||||||
totalItems: allItems.length,
|
totalItems: allItems.length,
|
||||||
totalPages: 1,
|
totalPages: 1,
|
||||||
items: allItems
|
items: allItems
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// Cache the result
|
// Helper function to refresh jobs cache in background
|
||||||
if (isRedisConnected()) {
|
async function refreshJobsCache(cacheKey: string, ttl: number, authHeader: string): Promise<void> {
|
||||||
|
try {
|
||||||
|
const result = await fetchAllJobsFromPocketBase(authHeader);
|
||||||
await setCache(cacheKey, result, ttl);
|
await setCache(cacheKey, result, ttl);
|
||||||
logLine('logs/server.log', `Cached ${cacheKey} with ${allItems.length} jobs for ${ttl}s`);
|
logLine('logs/server.log', `Background refresh: cached ${cacheKey} with ${result.items.length} jobs`);
|
||||||
}
|
|
||||||
|
|
||||||
return c.json(result);
|
|
||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logLine('logs/error.log', `jobs-all endpoint error: ${(err as Error)?.message || String(err)}`);
|
logLine('logs/error.log', `Background refresh error: ${(err as Error)?.message || String(err)}`);
|
||||||
return c.json({ error: 'Failed to fetch jobs' }, 500);
|
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
|
|
||||||
// --- Microsoft Graph helpers ---
|
// --- Microsoft Graph helpers ---
|
||||||
@@ -448,6 +473,31 @@ const PORT = Number(process.env.PORT || 3004);
|
|||||||
|
|
||||||
logLine('logs/server.log', `Starting frontend server (Redis version) on port ${PORT}`);
|
logLine('logs/server.log', `Starting frontend server (Redis version) on port ${PORT}`);
|
||||||
|
|
||||||
|
// Warm up cache on startup
|
||||||
|
(async () => {
|
||||||
|
try {
|
||||||
|
if (isRedisConnected()) {
|
||||||
|
logLine('logs/server.log', 'Warming up jobs cache...');
|
||||||
|
const result = await fetchAllJobsFromPocketBase('');
|
||||||
|
await setCache('jobs:all', result, 1800);
|
||||||
|
logLine('logs/server.log', `✓ Cache warmed with ${result.items.length} jobs`);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
logLine('logs/error.log', `Cache warmup failed: ${(err as Error)?.message || String(err)}`);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
|
// Background refresh every 5 minutes to keep cache hot
|
||||||
|
setInterval(async () => {
|
||||||
|
try {
|
||||||
|
if (isRedisConnected()) {
|
||||||
|
await refreshJobsCache('jobs:all', 1800, '');
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
logLine('logs/error.log', `Periodic refresh error: ${(err as Error)?.message || String(err)}`);
|
||||||
|
}
|
||||||
|
}, 5 * 60 * 1000); // Every 5 minutes
|
||||||
|
|
||||||
// Graceful shutdown logging
|
// Graceful shutdown logging
|
||||||
const shutdown = (signal: string) => {
|
const shutdown = (signal: string) => {
|
||||||
logLine('logs/server.log', `Shutting down due to ${signal}`);
|
logLine('logs/server.log', `Shutting down due to ${signal}`);
|
||||||
|
|||||||
Reference in New Issue
Block a user