I am using SQL Server for my database. I want to cache the result from API endpoints because the app is taking too much time initially to load as we have images/audios as files. I have implemented redis in order to cache the result and improve upon initial load time. It is running locally fine, but when I deploy this on the server, it did not show any improvement – rather it delays.
This is my controller endpoint:
[ResponseCache(CacheProfileName = "Default604800")]
public class BookController : BaseApiController
{
private readonly ILogger<BookController> _logger;
private readonly IDistributedCache _cache;
public readonly IConnectionMultiplexer _redis;
public BookController(IDistributedCache cache, IConnectionMultiplexer redis, ILogger<BookController> logger)
{
_cache = cache;
_redis = redis;
_logger = logger;
}
[AllowAnonymous]
[HttpGet("getBooks")]
[Produces("application/json")]
//[OutputCache(Duration = 604800)]
public async Task<IActionResult> GetBooks([FromQuery] BookParams param)
{
_logger.LogInformation("Alhamdulillah. Starting getBooks endpoint....");
Stopwatch stopwatch = Stopwatch.StartNew();
try
{
var cacheKey = $"Books_{param.Status}_{param.PageSize}_{param.OrderBy}_{param.OrderAs}";
var cachedData = await GetBookFromRedis(cacheKey);
if (cachedData != null)
{
var books = JsonConvert.DeserializeObject<List<BookDto>>(cachedData);
return Ok(books);
}
var result = await mdtr.Send(new List.Query { Params = param });
if (result != null && result.Value != null)
{
var pagedList = (PagedList<BookDto>)result.Value;
var items = pagedList.ToList();
var serializedBooks = JsonConvert.SerializeObject(items);
await StoreBookInRedis(cacheKey, serializedBooks);
return Ok(items);
}
else
{
return BadRequest("Failed to retrieve books.");
}
}
catch (Exception ex)
{
return StatusCode(500, $"Internal server error: {ex.Message}");
}
finally
{
stopwatch.Stop();
_logger.LogInformation("getBooks endpoints completed in ${Elapsedmilliseconds} ms", stopwatch.ElapsedMilliseconds);
}
}
private async Task<string> GetBookFromRedis(string cachekey)
{
try
{
var db = _redis.GetDatabase();
var cacheData = await db.StringGetAsync(cachekey);
return cacheData;
}
catch (Exception ex)
{
Console.WriteLine($"Error fetching data from redis, {ex.Message}");
return null;
}
}
private async Task StoreBookInRedis(string cacheKey, string serializedBook)
{
try
{
var db = _redis.GetDatabase();
await db.StringSetAsync(cacheKey, serializedBook, TimeSpan.FromSeconds(604800));
}
catch (Exception ex)
{
Console.WriteLine($"Error saving on redis, {ex.Message}");
}
}
}
Redis connection is configured in appSettings.json
:
"ConnectionStrings": {
"MyRedisConStr": "localhost:6379,abortConnect=false",
....
}
And I added another configuration and dependency inside program.cs
like this:
builder.Services.AddStackExchangeRedisCache(options =>
{
options.Configuration = builder.Configuration.GetConnectionString("MyRedisConStr");
options.InstanceName = "SampleInstance";
});
builder.Services.AddSingleton<IConnectionMultiplexer>(x =>
{
var connection = ConnectionMultiplexer.Connect("localhost");
connection.ConnectionFailed += (sender, e) =>
{
Console.WriteLine("Redis connection failed.");
};
return connection;
});
I have configured serilog to diagnose the performance bottleneck. I am using SQL Server as database.
Any insight/advice for diagnosing issue in production as to why redis is not performing in production while in localhost it is working fine is much appreciated.
My docker-compose.yaml
in production is
redis:
image: redis
container_name: my-redis
volumes:
- ./redis-data:/data
ports:
- "6379:6379"
environment:
- REDIS_CONNECTION_STRING=Redis
- REDIS_MAXMEMORY=5gb
user: root
restart: unless-stopped
networks:
- my-nw