working on region clearing cache, if using cachemanager back plance this would clear all servers in cluster

This commit is contained in:
Tom Gardham-Pallister 2017-06-26 19:10:20 +01:00
parent 26e7621798
commit 239dcfb6bd
8 changed files with 155 additions and 12 deletions

View File

@ -1,11 +1,13 @@
using System; using System;
using System.Collections.Generic;
namespace Ocelot.Cache namespace Ocelot.Cache
{ {
public interface IOcelotCache<T> public interface IOcelotCache<T>
{ {
void Add(string key, T value, TimeSpan ttl); void Add(string key, T value, TimeSpan ttl, string region);
void AddAndDelete(string key, T value, TimeSpan ttl); void AddAndDelete(string key, T value, TimeSpan ttl, string region);
T Get(string key); T Get(string key);
void ClearRegion(string region);
} }
} }

View File

@ -63,7 +63,9 @@ namespace Ocelot.Cache.Middleware
var response = HttpResponseMessage; var response = HttpResponseMessage;
_outputCache.Add(downstreamUrlKey, response, TimeSpan.FromSeconds(DownstreamRoute.ReRoute.FileCacheOptions.TtlSeconds)); var region = $"{DownstreamRoute.ReRoute.UpstreamHttpMethod}-{DownstreamRoute.ReRoute.UpstreamPathTemplate.Value}";
_outputCache.Add(downstreamUrlKey, response, TimeSpan.FromSeconds(DownstreamRoute.ReRoute.FileCacheOptions.TtlSeconds), region);
_logger.LogDebug("finished response added to cache for {downstreamUrlKey}", downstreamUrlKey); _logger.LogDebug("finished response added to cache for {downstreamUrlKey}", downstreamUrlKey);
} }

View File

@ -1,4 +1,6 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using CacheManager.Core; using CacheManager.Core;
namespace Ocelot.Cache namespace Ocelot.Cache
@ -6,18 +8,21 @@ namespace Ocelot.Cache
public class OcelotCacheManagerCache<T> : IOcelotCache<T> public class OcelotCacheManagerCache<T> : IOcelotCache<T>
{ {
private readonly ICacheManager<T> _cacheManager; private readonly ICacheManager<T> _cacheManager;
private HashSet<string> _keys;
public OcelotCacheManagerCache(ICacheManager<T> cacheManager) public OcelotCacheManagerCache(ICacheManager<T> cacheManager)
{ {
_cacheManager = cacheManager; _cacheManager = cacheManager;
_keys = new HashSet<string>();
} }
public void Add(string key, T value, TimeSpan ttl) public void Add(string key, T value, TimeSpan ttl, string region)
{ {
_cacheManager.Add(new CacheItem<T>(key, value, ExpirationMode.Absolute, ttl)); _cacheManager.Add(new CacheItem<T>(key, region, value, ExpirationMode.Absolute, ttl));
_keys.Add(key);
} }
public void AddAndDelete(string key, T value, TimeSpan ttl) public void AddAndDelete(string key, T value, TimeSpan ttl, string region)
{ {
var exists = _cacheManager.Get(key); var exists = _cacheManager.Get(key);
@ -26,12 +31,17 @@ namespace Ocelot.Cache
_cacheManager.Remove(key); _cacheManager.Remove(key);
} }
_cacheManager.Add(new CacheItem<T>(key, value, ExpirationMode.Absolute, ttl)); Add(key, value, ttl, region);
} }
public T Get(string key) public T Get(string key)
{ {
return _cacheManager.Get<T>(key); return _cacheManager.Get<T>(key);
} }
public void ClearRegion(string region)
{
_cacheManager.ClearRegion(region);
}
} }
} }

View File

@ -68,7 +68,7 @@ namespace Ocelot.Configuration.Repository
if (result.Response) if (result.Response)
{ {
_cache.AddAndDelete(_ocelotConfiguration, ocelotConfiguration, TimeSpan.FromSeconds(3)); _cache.AddAndDelete(_ocelotConfiguration, ocelotConfiguration, TimeSpan.FromSeconds(3), "OcelotConfiguration");
return new OkResponse(); return new OkResponse();
} }

View File

@ -0,0 +1,33 @@
using System.Net.Http;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Ocelot.Cache;
namespace Ocelot.Controllers
{
[Authorize]
[Route("cache")]
public class OutputCacheController : Controller
{
private IOcelotCache<HttpResponseMessage> _cache;
public OutputCacheController(IOcelotCache<HttpResponseMessage> cache)
{
_cache = cache;
}
[HttpGet]
public IActionResult Get()
{
return new NotFoundResult();
}
[HttpDelete]
[Route("{region}")]
public IActionResult Delete(string region)
{
_cache.ClearRegion(region);
return new NoContentResult();
}
}
}

View File

@ -1,4 +1,5 @@
using System; using System;
using System.Collections.Generic;
using CacheManager.Core; using CacheManager.Core;
using Moq; using Moq;
using Ocelot.Cache; using Ocelot.Cache;
@ -16,12 +17,14 @@ namespace Ocelot.UnitTests.Cache
private string _value; private string _value;
private string _resultGet; private string _resultGet;
private TimeSpan _ttlSeconds; private TimeSpan _ttlSeconds;
private List<string> _resultKeys;
public CacheManagerCacheTests() public CacheManagerCacheTests()
{ {
_mockCacheManager = new Mock<ICacheManager<string>>(); _mockCacheManager = new Mock<ICacheManager<string>>();
_ocelotOcelotCacheManager = new OcelotCacheManagerCache<string>(_mockCacheManager.Object); _ocelotOcelotCacheManager = new OcelotCacheManagerCache<string>(_mockCacheManager.Object);
} }
[Fact] [Fact]
public void should_get_from_cache() public void should_get_from_cache()
{ {
@ -29,7 +32,6 @@ namespace Ocelot.UnitTests.Cache
.When(x => x.WhenIGetFromTheCache()) .When(x => x.WhenIGetFromTheCache())
.Then(x => x.ThenTheResultIs("someValue")) .Then(x => x.ThenTheResultIs("someValue"))
.BDDfy(); .BDDfy();
} }
[Fact] [Fact]
@ -40,13 +42,37 @@ namespace Ocelot.UnitTests.Cache
.BDDfy(); .BDDfy();
} }
[Fact]
public void should_delete_key_from_cache()
{
this.Given(_ => GivenTheFollowingRegion("fookey"))
.When(_ => WhenIDeleteTheRegion("fookey"))
.Then(_ => ThenTheRegionIsDeleted("fookey"))
.BDDfy();
}
private void WhenIDeleteTheRegion(string region)
{
_ocelotOcelotCacheManager.ClearRegion(region);
}
private void ThenTheRegionIsDeleted(string region)
{
_mockCacheManager
.Verify(x => x.ClearRegion(region), Times.Once);
}
private void GivenTheFollowingRegion(string key)
{
_ocelotOcelotCacheManager.Add(key, "doesnt matter", TimeSpan.FromSeconds(10), "region");
}
private void WhenIAddToTheCache(string key, string value, TimeSpan ttlSeconds) private void WhenIAddToTheCache(string key, string value, TimeSpan ttlSeconds)
{ {
_key = key; _key = key;
_value = value; _value = value;
_ttlSeconds = ttlSeconds; _ttlSeconds = ttlSeconds;
_ocelotOcelotCacheManager.Add(_key, _value, _ttlSeconds, "region");
_ocelotOcelotCacheManager.Add(_key, _value, _ttlSeconds);
} }
private void ThenTheCacheIsCalledCorrectly() private void ThenTheCacheIsCalledCorrectly()

View File

@ -124,7 +124,7 @@ namespace Ocelot.UnitTests.Cache
private void ThenTheCacheAddIsCalledCorrectly() private void ThenTheCacheAddIsCalledCorrectly()
{ {
_cacheManager _cacheManager
.Verify(x => x.Add(It.IsAny<string>(), It.IsAny<HttpResponseMessage>(), It.IsAny<TimeSpan>()), Times.Once); .Verify(x => x.Add(It.IsAny<string>(), It.IsAny<HttpResponseMessage>(), It.IsAny<TimeSpan>(), It.IsAny<string>()), Times.Once);
} }
private void GivenResponseIsNotCached() private void GivenResponseIsNotCached()

View File

@ -0,0 +1,70 @@
using Xunit;
using Shouldly;
using TestStack.BDDfy;
using Ocelot.Controllers;
using System;
using Moq;
using Ocelot.Cache;
using System.Net.Http;
using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc;
namespace Ocelot.UnitTests.Controllers
{
public class OutputCacheControllerTests
{
private OutputCacheController _controller;
private Mock<IOcelotCache<HttpResponseMessage>> _cache;
private IActionResult _result;
public OutputCacheControllerTests()
{
_cache = new Mock<IOcelotCache<HttpResponseMessage>>();
_controller = new OutputCacheController(_cache.Object);
}
[Fact]
public void should_get_all_keys_from_server()
{
this.Given(_ => GivenTheFollowingKeys(new List<string>{"b", "a"}))
.When(_ => WhenIGetTheKeys())
.Then(_ => ThenTheKeysAreReturned())
.BDDfy();
}
[Fact]
public void should_delete_key()
{
this.When(_ => WhenIDeleteTheKey("a"))
.Then(_ => ThenTheKeyIsDeleted("a"))
.BDDfy();
}
private void ThenTheKeyIsDeleted(string key)
{
_result.ShouldBeOfType<NoContentResult>();
_cache
.Verify(x => x.ClearRegion(key), Times.Once);
}
private void WhenIDeleteTheKey(string key)
{
_result = _controller.Delete(key);
}
private void GivenTheFollowingKeys(List<string> keys)
{
}
private void WhenIGetTheKeys()
{
_result = _controller.Get();
}
private void ThenTheKeysAreReturned()
{
_result.ShouldBeOfType<OkObjectResult>();
}
}
}