mirror of
https://github.com/R0m1k3/noteflow.git
synced 2026-10-11 17:29:37 +02:00
Performance: Optimisations majeures + Auto-refresh RSS
Problèmes résolus: ✅ Flux RSS ne s'affichaient pas → LEFT JOIN + COALESCE ✅ Pas de mise à jour automatique → Scheduler toutes les 5min ✅ Application lente → Cache serveur + client Scheduler RSS (services/rss-scheduler.js): - Mise à jour automatique des flux toutes les 5 minutes - Première exécution 5 secondes après démarrage - Gestion parallèle de tous les flux activés - Logs détaillés pour debugging - Protection contre les exécutions multiples simultanées - Limite de 20 articles par flux pour performance Routes RSS optimisées: - Cache serveur 30 secondes pour /api/rss/articles - Invalidation cache après fetch manuel - LEFT JOIN au lieu de INNER JOIN (flux sans articles) - COALESCE pour titre fallback - Logs améliorés avec compteurs Frontend vanilla JS: - Auto-refresh RSS toutes les 30 secondes - Cache settings client 1 minute - Synchronisation avec scheduler serveur - console.debug au lieu de console.error pour auto-refresh Frontend React: - Auto-refresh RSS toutes les 30 secondes - loadRssData() séparée pour refresh indépendant - useEffect cleanup proper (clearInterval) - État lastUpdate pour tracking Server.js: - Démarrage scheduler au startup - Log confirmation démarrage Performances: - Moins de requêtes DB grâce au cache - Refresh automatique sans action utilisateur - Articles toujours à jour (max 30s de délai) - Support de beaucoup de flux RSS sans ralentissement
This commit is contained in:
5 files changed
+211
-57
No files matched your search
+29
-49
@@ -112,78 +112,58 @@ router.delete('/feeds/:id', requireAdmin, async (req, res) => {
|
||||
|
||||
/**
|
||||
* POST /api/rss/fetch
|
||||
* Récupérer tous les articles des flux actifs
|
||||
* Récupérer manuellement les articles de tous les flux RSS activés
|
||||
*/
|
||||
router.post('/fetch', requireAdmin, async (req, res) => {
|
||||
try {
|
||||
const feeds = await getAll('SELECT * FROM rss_feeds WHERE enabled = 1');
|
||||
const rssScheduler = require('../services/rss-scheduler');
|
||||
await rssScheduler.manualFetch();
|
||||
|
||||
let totalArticles = 0;
|
||||
// Invalider le cache
|
||||
articlesCache = null;
|
||||
articlesCacheTime = 0;
|
||||
|
||||
for (const feed of feeds) {
|
||||
try {
|
||||
const parsedFeed = await parser.parseURL(feed.url);
|
||||
|
||||
// Mettre à jour les infos du flux
|
||||
await runQuery(
|
||||
'UPDATE rss_feeds SET title = ?, description = ?, last_fetched_at = CURRENT_TIMESTAMP WHERE id = ?',
|
||||
[parsedFeed.title || feed.url, parsedFeed.description || '', feed.id]
|
||||
);
|
||||
|
||||
// Ajouter les articles
|
||||
for (const item of parsedFeed.items) {
|
||||
try {
|
||||
// Vérifier si l'article existe déjà
|
||||
const existing = await getOne('SELECT id FROM rss_articles WHERE link = ?', [item.link]);
|
||||
|
||||
if (!existing) {
|
||||
await runQuery(
|
||||
'INSERT INTO rss_articles (feed_id, title, link, description, pub_date, content) VALUES (?, ?, ?, ?, ?, ?)',
|
||||
[
|
||||
feed.id,
|
||||
item.title || '',
|
||||
item.link || '',
|
||||
item.contentSnippet || item.description || '',
|
||||
item.pubDate || item.isoDate || new Date().toISOString(),
|
||||
item.content || item['content:encoded'] || ''
|
||||
]
|
||||
);
|
||||
totalArticles++;
|
||||
}
|
||||
} catch (articleError) {
|
||||
// Ignorer les articles en double ou invalides
|
||||
logger.warn(`Erreur lors de l'ajout d'un article: ${articleError.message}`);
|
||||
}
|
||||
}
|
||||
} catch (feedError) {
|
||||
logger.error(`Erreur lors du fetch du flux ${feed.url}:`, feedError);
|
||||
}
|
||||
}
|
||||
|
||||
logger.info(`${totalArticles} nouveaux articles récupérés`);
|
||||
res.json({ message: `${totalArticles} nouveaux articles récupérés` });
|
||||
res.json({ message: 'Mise à jour des flux RSS terminée avec succès' });
|
||||
} catch (error) {
|
||||
logger.error('Erreur lors du fetch des flux RSS:', error);
|
||||
logger.error('Erreur lors du fetch manuel des flux RSS:', error);
|
||||
res.status(500).json({ error: 'Erreur serveur' });
|
||||
}
|
||||
});
|
||||
|
||||
// Cache pour les articles RSS (30 secondes)
|
||||
let articlesCache = null;
|
||||
let articlesCacheTime = 0;
|
||||
const ARTICLES_CACHE_DURATION = 30000; // 30 secondes
|
||||
|
||||
/**
|
||||
* GET /api/rss/articles
|
||||
* Récupérer les 5 derniers articles
|
||||
* Récupérer les 5 derniers articles (avec cache)
|
||||
*/
|
||||
router.get('/articles', async (req, res) => {
|
||||
try {
|
||||
// Utiliser le cache si disponible et récent
|
||||
const now = Date.now();
|
||||
if (articlesCache && (now - articlesCacheTime) < ARTICLES_CACHE_DURATION) {
|
||||
logger.debug('Articles RSS servis depuis le cache');
|
||||
return res.json(articlesCache);
|
||||
}
|
||||
|
||||
const articles = await getAll(`
|
||||
SELECT
|
||||
a.id, a.title, a.link, a.description, a.pub_date, a.content,
|
||||
f.title as feed_title, f.url as feed_url
|
||||
COALESCE(f.title, f.url) as feed_title, f.url as feed_url
|
||||
FROM rss_articles a
|
||||
JOIN rss_feeds f ON a.feed_id = f.id
|
||||
LEFT JOIN rss_feeds f ON a.feed_id = f.id
|
||||
WHERE a.pub_date IS NOT NULL
|
||||
ORDER BY a.pub_date DESC
|
||||
LIMIT 5
|
||||
`);
|
||||
|
||||
// Mettre en cache
|
||||
articlesCache = articles || [];
|
||||
articlesCacheTime = now;
|
||||
|
||||
logger.info(`Articles RSS récupérés: ${articles?.length || 0}`);
|
||||
res.json(articles || []);
|
||||
} catch (error) {
|
||||
logger.error('Erreur lors de la récupération des articles RSS:', error);
|
||||
|
||||
Reference in new issue
Block a user