Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LongRunning shouldn't run more than once #173

Open
laukoksoon opened this issue Feb 22, 2022 · 1 comment
Open

LongRunning shouldn't run more than once #173

laukoksoon opened this issue Feb 22, 2022 · 1 comment
Labels

Comments

@laukoksoon
Copy link

Describe the bug
My goal here is to cache some long running process data and then upon expiration, i will get those data that going to expired and append new delta changes from database
The long running process shouldn't run more than one time

To Reproduce
I will attach the console program that i wrote to reproduce the issue

When i set
int parallelNumber = 100; // 100 or below => All the thing run as EXPECTED

When i set
int parallelNumber = 300; // 300 or allow => Long process called more than once .. [NOT OK]

Expected behavior
Long process should call ONE even the parallel count set to 300 above

** Framework and Platform

  • OS: Windows 10
  • Framework v4.6.2
  • LazyCache Version 2.4

Console source code

using LazyCache;
using Microsoft.Extensions.Caching.Memory;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp1
{
class program
{
private static IAppCache _lazyCache;
private static int _totalLongProcess;
private static int _totalAppendProcess;

    static List<int> LongProcess(string key)
    {
        _totalLongProcess++;

        if (_totalLongProcess > 1)
        {
            throw new Exception("Not suppose to run more than one time");
        }

        Console.WriteLine("LONG PROCESS for key " + key);
        Thread.Sleep(5 * 1000);
        return Enumerable.Range(0, 100).ToList();
    }

    static List<int> AppendElement(string key, List<int> ori)
    {
        _totalAppendProcess++;
        Console.WriteLine("Append Process for key " + key);
        Thread.Sleep(2 * 1000);

        var newList = new List<int>();
        newList.Add(12345);
        newList.Add(54321);

        ori.AddRange(newList);
        return ori;
    }

    static List<int> GetCacheByKey(string key, string threadId)
    {
        Console.WriteLine($"Request key {key}, threadId {threadId}");
        var result = _lazyCache.GetOrAdd(key, () => LongProcess(key), GetOptions());
        return result;
    }

    static MemoryCacheEntryOptions GetOptions()
    {
        //ensure the cache item expires exactly on 30s (and not lazily on the next access)
        var options = new LazyCacheEntryOptions()
            .SetAbsoluteExpiration(TimeSpan.FromSeconds(10), ExpirationMode.ImmediateExpiration);
                    
        // as soon as it expires, re-add it to the cache
        options.RegisterPostEvictionCallback((keyEvicted, value, reason, state) =>
        {
            // dont re-add if running out of memory or it was forcibly removed
            if (reason == EvictionReason.Expired || reason == EvictionReason.TokenExpired)
            {
                var oriList = value as List<int>;
                _lazyCache.GetOrAdd(keyEvicted.ToString(), _ => AppendElement(keyEvicted.ToString(), oriList), GetOptions()); //calls itself to get another set of options!
            }
        });
        return options;
    }

    static void Main(string[] args)
    {
        _lazyCache = new CachingService();

        int round = 1;
        int i = 0;
        while (i < round)
        {
            int parallelNumber = 300;
            Parallel.For(0, parallelNumber, count =>
            {
                Thread.Sleep(1 * 1000);
                var list = GetCacheByKey("1", Thread.CurrentThread.ManagedThreadId.ToString());
                Console.WriteLine($"Got result for key {"1"}, threadId {Thread.CurrentThread.ManagedThreadId.ToString()}, count {list.Count}");
            });

            i++;
        }

        Console.WriteLine("Total long process run: " + _totalLongProcess);
        Console.WriteLine("Total append process run: " + _totalAppendProcess);
        Console.ReadLine();
    }
}

}

@laukoksoon laukoksoon added the bug label Feb 22, 2022
@alastairtree
Copy link
Owner

How long does the 300 version take? Your code only has 10s (not 30s as commented) - could it be longer than 10?

Also your expiration code is wrong - it should be using DateTiemOffset

new LazyCacheEntryOptions().SetAbsoluteExpiration(DateTimeOffset.Now.AddSeconds(10))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants