Je souhaite mettre en cache certaines données dans notre boutique en ligne pendant 1 heure et j'utilise Asp.Net Core 2.1
IMemoryCache
. Est-il possible de mettre à jour automatiquement le cache toutes les heures?
Normalement, le cache sera actualisé après qu'un utilisateur Web demande des données en cache qui ont expiré. Mais le processus de mise en cache prend un certain temps et je veux être sûr qu'aucun utilisateur n'obtienne un site Web `` lent '' car sa demande réinitialise certaines données mises en cache.
Je ne trouve aucun IMemoryCache code> pour ce faire. Je pense que c'est possible avec une tâche planifiée qui déclenche des fonctions de mise à jour toutes les heures (+1 seconde?), Mais avec un peu de malchance, la tâche planifiée est juste un peu plus tard, puis une demande utilisateur et l'utilisateur met à jour le cache au lieu ma tâche planifiée.
return _cache.GetOrCreate("FullNav", entry => { entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(1); //calculate fullnav return fullnav; });
Quelle est la meilleure façon de procéder?
3 Réponses :
vous pouvez utiliser la version AbsoluteExpiration
var cacheEntry = _cache.GetOrCreate(CacheKeys.Entry, entry => { entry.AbsoluteExpiration = TimeSpan.FromHours(1); return DateTime.Now; }); return View("Cache", cacheEntry);
GetOrCreate
, qui est suggérée par @Panagiotis Kavavos
XXX
Modifier
Obtient ou définit une date d'expiration absolue pour l'entrée de cache.
Obtient ou définit une heure d'expiration absolue, par rapport à maintenant.
AbsoluteExpirationRelativeToNow est spécifique au décalage horaire, alors qu'AbsoluteExpiration est spécifique à la date.
GetOrCreate
avec AbsoluteExpiration
est plus sûr dans ce cas. Utiliser TryGet
une condition de concurrence si deux ou plusieurs requêtes essaient de faire le même appel.
Ce code fera simplement ce que fait le code de la question d'origine. Il le fera en utilisant plus de lignes de code, étant également moins sûr pour les threads.
OP utilise AbsoluteExpirationRelativeToNow
alors que je suggère AbsoluteExpiration
Eh bien, je pensais que le principal problème auquel était confronté l'OP était qu'il voulait éviter le délai de "cache froid" lorsqu'un utilisateur essaie d'obtenir un élément du cache après que l'élément a été purgé. Ce code résout-il ce problème?
@mortb ne pas définir de période d'expiration résoudrait le problème
Cette réponse semble en effet inutile, @mortb vous comprenez mon problème fr Je pense que PanagiotisKanavos a la solution dans les commentaires sur mon premier post dans son fil.
Implémentation naïve:
// add proper code to populate var x = "hello"; _cache.Set(x, NullChangeToken.Singleton); Task.Factory.StartNew(async () => { await Task.Delay(TimeSpan.FromHours(1)); // add proper code to repopulate var y = "new value"; _cache.Set(y, NullChangeToken.Singleton); });
Le NullChangeToken
ne changera jamais et donc la valeur n'expire pas automatiquement. La valeur sera remplacée par les appels suivants à _cache.Set(...)
L'implémentation ne prend pas en compte le fait que l'élément peut être purgé en raison de la pression de la mémoire. Je pense qu'il pourrait être préférable de l'implémenter en tant que classe de service instanciée en tant que singleton. La classe de service ferait la même chose, mais conserverait l'élément "cher" dans une variable d'instance.
Meilleure réponse donnée dans les commentaires de Panagiotis Kanavos:
Dans le code:
fullnav = ''; //calculate fullnav _cache.Set("FullNav",fullnav);
Lors de l'appel du fullnav mis en cache, il est judicieux d'utiliser TryGetValue
et d'appeler la méthode set lorsque le le cache n'est pas déjà disponible.
Vous pouvez essayer d'utiliser la méthode
RegisterPostEvictionCallback
pour enregistrer un rappel qui remplira à nouveau le cache: vibrantcode.com/AspNetDocsPreview/performance/caching/...Avez-vous vérifié le Définir les méthodes? Ou en utilisant AbsoluteExpiration au lieu de
AbsoluteExpirationRelativeToNow
?Vous ne devriez probablement pas utiliser l'expiration basée sur le temps du tout ou au moins une période plus longue que la tâche planifiée, de sorte que les entrées ne seront remplacées que par la tâche planifiée. Si vous réchauffez le cache au démarrage, vous n'aurez qu'à vous soucier des entrées expulsées en raison de la pression de la mémoire
Utilisez un cache mémoire distribué, tel que redis. Écrivez-y simplement (pas d'expiration) et lorsque nos données changent (c'est-à-dire que l'utilisateur modifie la description du produit), générez les nouvelles données et mettez à jour le cache, de cette façon, votre cache est toujours up2date et n'expire jamais. Vous pouvez également stocker les données générées dans une base de données (ou un système de fichiers) lorsqu'elles sont modifiées, puis les récupérer à partir de là en cas d'échec du cache. De cette façon, la génération se produit dans le backend où le cache manque le temps de traitement est réduit au minimum acheter uniquement la lecture des données de la base de données ou du système de fichiers
@PanagiotisKanavos Je n'ai pas trouvé les fonctions Set et je m'attendais à ce qu'AbsoluteExpiration et AbsoluteExpirationRelativeToNow fassent presque la même chose (et parce que je voulais mettre des éléments en cache pendant 1 heure à partir de maintenant, j'ai choisi la deuxième. Mais je pense que vous voulez dire que c'est la meilleure façon ne définissez pas de délai d'expiration et utilisez la fonction Set dans une tâche planifiée pour recalculer les valeurs du cache, non?
@Tseng J'aime votre solution, mais elle ne correspondra pas à mon projet actuel car les données sont générées en externe et je ne sais pas quand il y a des changements.