1
votes

Mettre à jour IMemoryCache côté serveur

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?


6 commentaires

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.


3 Réponses :


2
votes

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.

Rerefence

AbsoluteExpirationRelativeToNow est spécifique au décalage horaire, alors qu'AbsoluteExpiration est spécifique à la date.


6 commentaires

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.



0
votes

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.


0 commentaires

0
votes

Meilleure réponse donnée dans les commentaires de Panagiotis Kanavos:

  1. Utilisez Set () au lieu de GetOrCreate () pour forcer une réinitialisation du cache, même s'il existe déjà. Lien
  2. N'utilisez pas de délai d'expiration, même AbsoluteExpiration n'est pas nécessaire.
  3. Créez une tâche planifiée qui appelle cette méthode à chaque fois

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.


0 commentaires