2017-06-13 72 views
1

我们在OrmLite Provider(MySql)中使用serviceStack缓存。我们注意到,当我们创建带有失效日期的缓存键时,在失效日期到来之后键不会被删除。相反,他们在“ExpiryDate”列中获得NULL值。因此,当我们计算Cache.GetTimeToLive()时会导致奇怪的值。ServiceStack Ormlite缓存条目在到期后不会被删除

这是一个serviceStack中的错误还是在我们的密钥创建代码?我们使用的版本ServiceStack(4.5.4)和OrmLite版本(4.5.4)

 IAppSettings appSettings = new AppSettings(); 

     var userConsultsPerHourLimit = appSettings.Get<int>("throttling:consultations:requests:perHourLimit"); 
     var userConsultsPerDayLimit = appSettings.Get<int>("throttling:consultations:requests:perDayLimit"); 
     var userConsultsPerMonthLimit = appSettings.Get<int>("throttling:consultations:requests:perMonthLimit"); 

     var userConsultsMadePerHour = Cache.GetOrCreate<int>(UserConsultPerHourCacheKey, TimeSpan.FromHours(1),() => { return 0; }); 
     var userConsultsMadePerDay = Cache.GetOrCreate<int>(UserConsultPerDayCacheKey, TimeSpan.FromDays(1),() => { return 0; }); 
     var userConsultsMadePerMonth = Cache.GetOrCreate<int>(UserConsultPerMonthCacheKey, (new DateTime(DateTime.UtcNow.Year, DateTime.UtcNow.Month, 1).AddMonths(1).AddDays(-1) - DateTime.UtcNow),() => { return 0; }); 

     string retryAfter = System.Threading.Thread.CurrentThread.CurrentCulture.Name == "ar-SA" ? "يوم" : "day"; 

     bool shouldThrottleRequest = false; 
     bool didExceedMonthlyLimit = false; 

     if (userConsultsMadePerHour >= userConsultsPerHourLimit) 
     { 
      shouldThrottleRequest = true; 
      TimeSpan? timeToLive = Cache.GetTimeToLive(UserConsultPerHourCacheKey); 
      if (timeToLive.HasValue) 
       retryAfter = Humanizer.TimeSpanHumanizeExtensions.Humanize(timeToLive.Value, 2, System.Threading.Thread.CurrentThread.CurrentUICulture); 
     } 
     else if (userConsultsMadePerDay >= userConsultsPerDayLimit) 
     { 
      shouldThrottleRequest = true; 
      TimeSpan? timeToLive = Cache.GetTimeToLive(UserConsultPerDayCacheKey); 
      if (timeToLive.HasValue) 
       retryAfter = Humanizer.TimeSpanHumanizeExtensions.Humanize(timeToLive.Value, 2, System.Threading.Thread.CurrentThread.CurrentUICulture); 
     } 
     else if (userConsultsMadePerMonth >= userConsultsPerMonthLimit) 
     { 
      shouldThrottleRequest = true; 
      TimeSpan? timeToLive = Cache.GetTimeToLive(UserConsultPerMonthCacheKey); 
      if (timeToLive.HasValue) 
       retryAfter = Humanizer.TimeSpanHumanizeExtensions.Humanize(timeToLive.Value, 3, System.Threading.Thread.CurrentThread.CurrentUICulture); 
      didExceedMonthlyLimit = true; 
     } 

回答

1

我认为我们已经深入到底..它是由于我们身边的缓存API的滥用造成的......我们在其他不同地方发现API调用“Increment”和“Decrement”API导致密钥(超过有效期的那些人)将被删除(通过内部调用来验证方法),然后从头开始重新创建(但没有过期日期)。解决方法是在调用Increment/Decrement之前调用GetOrCreate以确保密钥在事实上是存在的,如果没有,用新鲜的到期日价值重新创建它..

2

这是在该行取一个过期的缓存条目后删除ServiceStack的最新版本working as expected

var ormliteCache = Cache as OrmLiteCacheClient; 
var key = "int:key"; 

var value = Cache.GetOrCreate(key, TimeSpan.FromMilliseconds(100),() => 1); 
var ttl = Cache.GetTimeToLive(key); 

using (var db = ormliteCache.DbFactory.OpenDbConnection()) 
{ 
    var row = db.SingleById<CacheEntry>(key); 
    Assert.That(row, Is.Not.Null); 
    Assert.That(row.ExpiryDate, Is.Not.Null); 
} 

Assert.That(value, Is.EqualTo(1)); 
Assert.That(ttl.Value.TotalMilliseconds, Is.GreaterThan(0)); 

Thread.Sleep(200); 
value = Cache.Get<int>(key); 
ttl = Cache.GetTimeToLive(key); 

Assert.That(value, Is.EqualTo(0)); 
Assert.That(ttl, Is.Null); 

using (var db = ormliteCache.DbFactory.OpenDbConnection()) 
{ 
    var row = db.SingleById<CacheEntry>(key); 
    Assert.That(row, Is.Null); 
} 

我们注意到,当我们创建带有过期日期的缓存键时,在到期日到来之后键不会被删除。

的RDBMS不会自动按日期过期缓存条目,但解决缓存条目时OrmLiteCacheClient会自动删除过期的条目(如上面可以看出),所以它永远不会返回过期的条目。

相反,它们在“ExpiryDate”列中获得NULL值。

这是不可能的。 ExpiryDate仅在创建或替换现有条目时填充,它在到期时从未设置为空。当一个条目到期时,整个条目将被删除。

+0

感谢@mythz ..我看到,我们如何得到“NULL”值在“ExpiryDate”列所有那些键,在不手动操作它们?我们确信他们得到正确插入,看看日期在到期日期列.. 通过我们只使用GetOrCreate,递增和递减的API的方式..将在值的任何这些API的工作,但错误影响ExpiryDate例如,这就是在检查'cachentry'表时,我们如何看到NULL? –

+0

@MohammadZekrallah请把一个独立的清样,我们可以在本地运行,看这种行为,确保其运行的是最新版本 – mythz