新しいスレッドをトリガーして新しい値を設定しながら、古い値を提供するようにinprocMVCキャッシュを拡張しようとしています。
次のコードは、次の行を削除すると「機能」します。
ThreadPool.QueueUserWorkItem(delegate
「動作する」とは、キャッシュのリロードをトリガーしたリクエストを行ったクライアントが、キャッシュが更新されるまでブロックされることを意味しますが、他のすべてのクライアントはシャドウバージョンに対してロードを続けます。
理想的には、バックグラウンドで処理を実行し、キャッシュの更新をトリガーしたクライアントがその要求にシャドウコピーを使用するようにします。スレッドが完了した後で将来の要求を行うと、新しいキャッシュ値が提供されます。
私のソリューションは、DIフレームワークとしてCastleに大きく依存しています。私が抱えている問題は、CastleのLifeStylesに関係していると思います。エラーメッセージは次のとおりです。
HttpContext.Currentはnullです。PerWebRequestLifestyleはASP.Netでのみ使用できます
例外は、必要なコンポーネントを解決しようとしているときに、長時間実行されるプロセス( getCacheItem() )の奥深くで発生します。
私のキャッシュ方法は次のとおりです。
public T GetShadow<T>(string key, Func<T> getCacheItem, int timeOut)
{
if (Exists(key))
{
_log.Info("Shadow: Returning item from Cache: " + key);
return (T)HttpContext.Current.Cache[key];
}
var shadowKey = key + "-shadow";
if (Monitor.TryEnter(GetKeyLock(key)))
{
ThreadPool.QueueUserWorkItem(delegate
{
try
{
var item = getCacheItem(); // Long running query
// Replace the cache entry
HttpRuntime.Cache.Insert(key, item, null,
DateTime.UtcNow.AddMinutes(
timeOut), Cache.NoSlidingExpiration);
// And add its shadow for subsequent updates
HttpRuntime.Cache.Insert(shadowKey, item, null,
DateTime.UtcNow.AddMinutes(timeOut * 2), Cache.NoSlidingExpiration);
}
finally
{
Monitor.Exit(GetKeyLock(key));
}
});
}
while (!Exists(shadowKey))
{
Thread.Sleep(500);
}
return (T)HttpContext.Current.Cache[shadowKey];
}
だから私の質問は、MVC3内でスレッドの作成を正しく行っているかということです。
PWRのライフスタイルのためにウィンザーが例外をスローしないように、このシナリオでスレッドをスピンアップするためのより良い方法はありますか?