/** * Cache management routes * * Provides endpoints for cache status and manual sync triggers. */ import { Router, Request, Response } from 'express'; import { cacheStore } from '../services/cacheStore.js'; import { syncEngine } from '../services/syncEngine.js'; import { logger } from '../services/logger.js'; import { OBJECT_TYPES } from '../generated/jira-schema.js'; import type { CMDBObjectTypeName } from '../generated/jira-types.js'; const router = Router(); // Get cache status router.get('/status', async (req: Request, res: Response) => { try { const cacheStats = await cacheStore.getStats(); const syncStatus = await syncEngine.getStatus(); // Compare cache count with Jira count for ApplicationComponent let jiraComparison: { jiraCount?: number; cacheCount: number; difference?: number } | undefined; if (cacheStats.objectsByType['ApplicationComponent'] !== undefined) { try { const { jiraAssetsClient } = await import('../services/jiraAssetsClient.js'); const { OBJECT_TYPES } = await import('../generated/jira-schema.js'); const typeDef = OBJECT_TYPES['ApplicationComponent']; if (typeDef) { const searchResult = await jiraAssetsClient.searchObjects(`objectType = "${typeDef.name}"`, 1, 1); const jiraCount = searchResult.totalCount; const cacheCount = cacheStats.objectsByType['ApplicationComponent'] || 0; jiraComparison = { jiraCount, cacheCount, difference: jiraCount - cacheCount, }; } } catch (err) { logger.debug('Could not fetch Jira count for comparison', err); } } res.json({ cache: cacheStats, sync: syncStatus, supportedTypes: Object.keys(OBJECT_TYPES), jiraComparison, }); } catch (error) { logger.error('Failed to get cache status', error); res.status(500).json({ error: 'Failed to get cache status' }); } }); // Trigger full sync router.post('/sync', async (req: Request, res: Response) => { try { logger.info('Manual full sync triggered'); // Don't wait for completion - return immediately syncEngine.fullSync().catch(err => { logger.error('Full sync failed', err); }); res.json({ status: 'started', message: 'Full sync started in background', }); } catch (error) { logger.error('Failed to trigger full sync', error); res.status(500).json({ error: 'Failed to trigger sync' }); } }); // Trigger sync for a specific object type router.post('/sync/:objectType', async (req: Request, res: Response) => { try { const { objectType } = req.params; // Validate object type if (!OBJECT_TYPES[objectType]) { res.status(400).json({ error: `Unknown object type: ${objectType}`, supportedTypes: Object.keys(OBJECT_TYPES), }); return; } logger.info(`Manual sync triggered for ${objectType}`); const result = await syncEngine.syncType(objectType as CMDBObjectTypeName); res.json({ status: 'completed', objectType, stats: result, }); } catch (error) { const errorMessage = error instanceof Error ? error.message : 'Failed to sync object type'; logger.error(`Failed to sync object type ${req.params.objectType}`, error); // Return 409 (Conflict) if sync is already in progress, otherwise 500 const statusCode = errorMessage.includes('already in progress') ? 409 : 500; res.status(statusCode).json({ error: errorMessage, objectType: req.params.objectType, }); } }); // Clear cache for a specific type router.delete('/clear/:objectType', async (req: Request, res: Response) => { try { const { objectType } = req.params; if (!OBJECT_TYPES[objectType]) { res.status(400).json({ error: `Unknown object type: ${objectType}`, supportedTypes: Object.keys(OBJECT_TYPES), }); return; } logger.info(`Clearing cache for ${objectType}`); const deleted = await cacheStore.clearObjectType(objectType as CMDBObjectTypeName); res.json({ status: 'cleared', objectType, deletedCount: deleted, }); } catch (error) { logger.error(`Failed to clear cache for ${req.params.objectType}`, error); res.status(500).json({ error: 'Failed to clear cache' }); } }); // Clear entire cache router.delete('/clear', async (req: Request, res: Response) => { try { logger.info('Clearing entire cache'); await cacheStore.clearAll(); res.json({ status: 'cleared', message: 'Entire cache cleared', }); } catch (error) { logger.error('Failed to clear cache', error); res.status(500).json({ error: 'Failed to clear cache' }); } }); export default router;