From 565d1860a2ffa6bef37d189951b489e29b7f0380 Mon Sep 17 00:00:00 2001 From: moheladwy Date: Wed, 25 Dec 2024 00:00:50 +0200 Subject: [PATCH] Added Redis Caching Functionality to the solution Added Redis Service instead of In memory caching Added Redis Service in the docker-compose.yml file Added .dockerignore file --- .dockerignore | 10 +++ Todo.Api/appsettings.Development.json | 3 +- Todo.Api/appsettings.json | 2 +- Todo.Core/Interfaces/IRedisCacheService.cs | 66 +++++++++++++++++++ .../Configurations/Constants.cs | 1 + Todo.Infrastructure/Extensions.cs | 10 ++- .../{ => Cached}/CachedAccountRepository.cs | 45 ++++++------- .../{ => Cached}/CachedListRepository.cs | 57 ++++++++-------- .../{ => Cached}/CachedTasksRepository.cs | 56 ++++++++-------- .../{ => DB}/AccountRepository.cs | 2 +- .../Repositories/{ => DB}/ListRepository.cs | 2 +- .../{ => DB}/RefreshTokenRepository.cs | 2 +- .../Repositories/{ => DB}/TasksRepository.cs | 2 +- .../Services/RedisCachingService.cs | 34 ++++++++++ .../Todo.Infrastructure.csproj | 2 + Todo.sln | 2 + docker-compose.yml | 17 ++++- 17 files changed, 219 insertions(+), 94 deletions(-) create mode 100644 .dockerignore create mode 100644 Todo.Core/Interfaces/IRedisCacheService.cs rename Todo.Infrastructure/Repositories/{ => Cached}/CachedAccountRepository.cs (52%) rename Todo.Infrastructure/Repositories/{ => Cached}/CachedListRepository.cs (58%) rename Todo.Infrastructure/Repositories/{ => Cached}/CachedTasksRepository.cs (58%) rename Todo.Infrastructure/Repositories/{ => DB}/AccountRepository.cs (99%) rename Todo.Infrastructure/Repositories/{ => DB}/ListRepository.cs (99%) rename Todo.Infrastructure/Repositories/{ => DB}/RefreshTokenRepository.cs (98%) rename Todo.Infrastructure/Repositories/{ => DB}/TasksRepository.cs (99%) create mode 100644 Todo.Infrastructure/Services/RedisCachingService.cs diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..6863fdd --- /dev/null +++ b/.dockerignore @@ -0,0 +1,10 @@ +Jenkinsfile +LICENSE +README.md +.github +.gitignore +.idea +.vscode +Dockerfile +docker-compose.yml +.dockerignore \ No newline at end of file diff --git a/Todo.Api/appsettings.Development.json b/Todo.Api/appsettings.Development.json index 8f3da45..a5052ea 100644 --- a/Todo.Api/appsettings.Development.json +++ b/Todo.Api/appsettings.Development.json @@ -1,6 +1,7 @@ { "ConnectionStrings": { - "SqliteConnection": "Data Source=Database/todo.db" + "SqliteConnection": "Data Source=Database/todo.db", + "RedisConnection": "localhost:6379" }, "Logging": { "LogLevel": { diff --git a/Todo.Api/appsettings.json b/Todo.Api/appsettings.json index 92e7429..8a59dad 100644 --- a/Todo.Api/appsettings.json +++ b/Todo.Api/appsettings.json @@ -1,7 +1,7 @@ { "ConnectionStrings": { "SqliteConnection": "Data Source=Database/todo.db", - "SqlServerConnection": "Server=localhost,1433;Database=AuthDemo;User Id=sa;Password=23-7-2003@Mohamed;TrustServerCertificate=True;" + "RedisConnection": "localhost:6379" }, "Logging": { "LogLevel": { diff --git a/Todo.Core/Interfaces/IRedisCacheService.cs b/Todo.Core/Interfaces/IRedisCacheService.cs new file mode 100644 index 0000000..dc785aa --- /dev/null +++ b/Todo.Core/Interfaces/IRedisCacheService.cs @@ -0,0 +1,66 @@ +namespace Todo.Core.Interfaces; + +/// +/// Interface for Redis Cache Service +/// +public interface IRedisCacheService +{ + /// + /// Get data from Redis Cache + /// + /// + /// Key to get data from Redis Cache + /// + /// + /// Type of data to get from Redis Cache + /// + /// + /// Data from Redis Cache with the given key if exists, otherwise default value of the type + /// + Task GetData(string key); + + /// + /// Set data in Redis Cache + /// + /// + /// Key to set data in Redis Cache + /// + /// + /// Data to set in Redis Cache + /// + /// + /// Type of data to set in Redis Cache + /// + /// + /// A task that represents the asynchronous operation + /// + Task SetData(string key, T data); + + /// + /// Update data in Redis Cache + /// + /// + /// Key to update data in Redis Cache + /// + /// + /// Data to update in Redis Cache + /// + /// + /// Type of data to update in Redis Cache + /// + /// + /// A task that represents the asynchronous operation, containing the updated data + /// + Task UpdateData(string key, T data); + + /// + /// Remove data from Redis Cache + /// + /// + /// Key to remove data from Redis Cache + /// + /// + /// A task that represents the asynchronous operation + /// + Task RemoveData(string key); +} \ No newline at end of file diff --git a/Todo.Infrastructure/Configurations/Constants.cs b/Todo.Infrastructure/Configurations/Constants.cs index c216019..bd1703a 100644 --- a/Todo.Infrastructure/Configurations/Constants.cs +++ b/Todo.Infrastructure/Configurations/Constants.cs @@ -3,6 +3,7 @@ namespace Todo.Infrastructure.Configurations; public static class Constants { public const string ConnectionStringName = "SqliteConnection"; + public const string RedisConnectionStringName = "RedisConnection"; public const string JwtConfigurationsSectionKey = "JwtConfigurations"; public const string AllowedUserNameCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._@"; public const int TimeSpanByMinutesForCaching = 5; diff --git a/Todo.Infrastructure/Extensions.cs b/Todo.Infrastructure/Extensions.cs index f4872af..97f4abb 100644 --- a/Todo.Infrastructure/Extensions.cs +++ b/Todo.Infrastructure/Extensions.cs @@ -12,7 +12,8 @@ using Todo.Core.Interfaces; using Todo.Infrastructure.Configurations; using Todo.Infrastructure.DatabaseContexts; -using Todo.Infrastructure.Repositories; +using Todo.Infrastructure.Repositories.Cached; +using Todo.Infrastructure.Repositories.DB; using Todo.Infrastructure.Services; using Task = Todo.Core.Entities.Task; @@ -36,7 +37,12 @@ public static void RegisterRepositories(this WebApplicationBuilder builder) public static void RegisterCachingRepositories(this WebApplicationBuilder builder) { - builder.Services.AddMemoryCache(); + builder.Services.AddStackExchangeRedisCache(options => + { + options.Configuration = builder.Configuration.GetConnectionString(Constants.RedisConnectionStringName); + options.InstanceName = "TodoFullStack_"; + }); + builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped, CachedListRepository>(); builder.Services.AddScoped, CachedTasksRepository>(); diff --git a/Todo.Infrastructure/Repositories/CachedAccountRepository.cs b/Todo.Infrastructure/Repositories/Cached/CachedAccountRepository.cs similarity index 52% rename from Todo.Infrastructure/Repositories/CachedAccountRepository.cs rename to Todo.Infrastructure/Repositories/Cached/CachedAccountRepository.cs index 9596e6d..6323f10 100644 --- a/Todo.Infrastructure/Repositories/CachedAccountRepository.cs +++ b/Todo.Infrastructure/Repositories/Cached/CachedAccountRepository.cs @@ -1,39 +1,39 @@ using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; -using Microsoft.Extensions.Caching.Memory; using Todo.Core.DTOs.AccountDTOs; using Todo.Core.Entities; -using Todo.Core.Exceptions; using Todo.Core.Interfaces; -using Todo.Infrastructure.Configurations; +using Todo.Infrastructure.Repositories.DB; using Task = System.Threading.Tasks.Task; -namespace Todo.Infrastructure.Repositories; +namespace Todo.Infrastructure.Repositories.Cached; public class CachedAccountRepository : IAccountRepository { private readonly AccountRepository _accountRepository; - private readonly IMemoryCache _memoryCache; + private readonly IRedisCacheService _cacheService; - public CachedAccountRepository(AccountRepository accountRepository, IMemoryCache memoryCache) + /// + /// Initializes a new instance of the class. + /// + /// + /// + public CachedAccountRepository(AccountRepository accountRepository, IRedisCacheService cacheService) { _accountRepository = accountRepository; - _memoryCache = memoryCache; + _cacheService = cacheService; } public async Task GetUserById(string userId) { var cacheKey = $"User-{userId}"; - var cachedUser = await _memoryCache.GetOrCreateAsync( - cacheKey, - entry => - { - entry.SetAbsoluteExpiration(TimeSpan.FromMinutes(Constants.TimeSpanByMinutesForCaching)); - return _accountRepository.GetUserById(userId); - }); + var cachedUser = await _cacheService.GetData(cacheKey); + if (cachedUser is not null) return cachedUser; - return cachedUser ?? throw new UserNotFoundException($"User with id: {userId} not found"); + var user = await _accountRepository.GetUserById(userId); + await _cacheService.SetData(cacheKey, user); + return user; } public async Task GetUserByClaims(ClaimsPrincipal claims) @@ -46,25 +46,20 @@ public async Task GetUserByClaims(ClaimsPrincipal claims) public async Task ChangePassword(ChangePasswordDto changePasswordDto) { await _accountRepository.ChangePassword(changePasswordDto); - - var cacheKey = $"User-{changePasswordDto.Id}"; - _memoryCache.Remove(cacheKey); - _memoryCache.CreateEntry(cacheKey).Value = await _accountRepository.GetUserById(changePasswordDto.Id); + await _cacheService.UpdateData($"User-{changePasswordDto.Id}", + await _accountRepository.GetUserById(changePasswordDto.Id)); } public async Task UpdateUserInfo(UpdateUserInfoDto updateUserInfoDto) { await _accountRepository.UpdateUserInfo(updateUserInfoDto); - - var cacheKey = $"User-{updateUserInfoDto.Id}"; - _memoryCache.Remove(cacheKey); - _memoryCache.CreateEntry(cacheKey).Value = await _accountRepository.GetUserById(updateUserInfoDto.Id); + await _cacheService.UpdateData($"User-{updateUserInfoDto.Id}", + await _accountRepository.GetUserById(updateUserInfoDto.Id)); } public async Task DeleteAccount(string id) { await _accountRepository.DeleteAccount(id); - var cacheKey = $"User-{id}"; - _memoryCache.Remove(cacheKey); + await _cacheService.RemoveData($"User-{id}"); } } \ No newline at end of file diff --git a/Todo.Infrastructure/Repositories/CachedListRepository.cs b/Todo.Infrastructure/Repositories/Cached/CachedListRepository.cs similarity index 58% rename from Todo.Infrastructure/Repositories/CachedListRepository.cs rename to Todo.Infrastructure/Repositories/Cached/CachedListRepository.cs index 7b1ff99..3c4e326 100644 --- a/Todo.Infrastructure/Repositories/CachedListRepository.cs +++ b/Todo.Infrastructure/Repositories/Cached/CachedListRepository.cs @@ -1,52 +1,50 @@ -using Microsoft.Extensions.Caching.Memory; using Todo.Core.DTOs.ListDTOs; using Todo.Core.Entities; -using Todo.Core.Exceptions; using Todo.Core.Interfaces; -using Todo.Infrastructure.Configurations; +using Todo.Infrastructure.Repositories.DB; using Task = System.Threading.Tasks.Task; -namespace Todo.Infrastructure.Repositories; +namespace Todo.Infrastructure.Repositories.Cached; public class CachedListRepository : IRepository { private readonly ListRepository _listRepository; - private readonly IMemoryCache _memoryCache; - - public CachedListRepository(ListRepository listRepository, IMemoryCache memoryCache) + private readonly IRedisCacheService _cacheService; + + /// + /// Initializes a new instance of the class. + /// + /// + /// + public CachedListRepository(ListRepository listRepository, IRedisCacheService cacheService) { _listRepository = listRepository; - _memoryCache = memoryCache; + _cacheService = cacheService; } public async Task> GetAllAsync(string id) { var cacheKey = $"User-{id}-Lists"; - var cachedLists = await _memoryCache.GetOrCreateAsync>( - cacheKey, - entry => - { - entry.SetAbsoluteExpiration(TimeSpan.FromMinutes(Constants.TimeSpanByMinutesForCaching)); - return _listRepository.GetAllAsync(id); - }); + var cachedLists = await _cacheService.GetData>(cacheKey); + if (cachedLists is not null) return cachedLists; - return cachedLists ?? []; + var lists = await _listRepository.GetAllAsync(id); + var taskLists = lists.ToList(); + await _cacheService.SetData(cacheKey, taskLists); + return taskLists; } public async Task GetByIdAsync(Guid id) { var cacheKey = $"List-{id}"; - var cachedList = await _memoryCache.GetOrCreateAsync( - cacheKey, - entry => - { - entry.SetAbsoluteExpiration(TimeSpan.FromMinutes(Constants.TimeSpanByMinutesForCaching)); - return _listRepository.GetByIdAsync(id); - }); + var cachedList = await _cacheService.GetData(cacheKey); + if (cachedList is not null) return cachedList; - return cachedList ?? throw new ListNotFoundException($"The list with id: {id} was not found."); + var list = await _listRepository.GetByIdAsync(id); + await _cacheService.SetData(cacheKey, list); + return list; } public async Task AddAsync(AddListDto entity) @@ -61,8 +59,7 @@ public async Task UpdateAsync(UpdateListDto entity) var updatedList = await _listRepository.UpdateAsync(entity); var cacheKey = $"List-{entity.Id}"; - _memoryCache.Remove(cacheKey); - _memoryCache.CreateEntry(cacheKey).Value = updatedList; + await _cacheService.UpdateData(cacheKey, updatedList); var list = await _listRepository.GetByIdAsync(entity.Id); await UpdateAllListsInCache(list.UserId ?? throw new ArgumentNullException(list.UserId, @@ -78,8 +75,7 @@ public async Task DeleteAsync(Guid id) var list = await _listRepository.GetByIdAsync(id); await _listRepository.DeleteAsync(id); - _memoryCache.Remove($"List-{id}"); - + await _cacheService.RemoveData($"List-{id}"); await UpdateAllListsInCache(list.UserId ?? throw new ArgumentNullException(list.UserId, "The list with the given id does not have a user id.")); } @@ -87,7 +83,8 @@ public async Task DeleteAsync(Guid id) private async Task UpdateAllListsInCache(string userId) { var cacheKey = $"User-{userId}-Lists"; - _memoryCache.Remove(cacheKey); - _memoryCache.CreateEntry(cacheKey).Value = await _listRepository.GetAllAsync(userId); + var lists = await _listRepository.GetAllAsync(userId); + var taskLists = lists.ToList(); + await _cacheService.UpdateData(cacheKey, taskLists); } } \ No newline at end of file diff --git a/Todo.Infrastructure/Repositories/CachedTasksRepository.cs b/Todo.Infrastructure/Repositories/Cached/CachedTasksRepository.cs similarity index 58% rename from Todo.Infrastructure/Repositories/CachedTasksRepository.cs rename to Todo.Infrastructure/Repositories/Cached/CachedTasksRepository.cs index eeb269b..4671a22 100644 --- a/Todo.Infrastructure/Repositories/CachedTasksRepository.cs +++ b/Todo.Infrastructure/Repositories/Cached/CachedTasksRepository.cs @@ -1,51 +1,49 @@ -using Microsoft.Extensions.Caching.Memory; using Todo.Core.DTOs.TasksDtos; -using Todo.Core.Exceptions; using Todo.Core.Interfaces; -using Todo.Infrastructure.Configurations; +using Todo.Infrastructure.Repositories.DB; using Task_Entity = Todo.Core.Entities.Task; -namespace Todo.Infrastructure.Repositories; +namespace Todo.Infrastructure.Repositories.Cached; public class CachedTasksRepository : IRepository { private readonly TasksRepository _tasksRepository; - private readonly IMemoryCache _memoryCache; + private readonly IRedisCacheService _cacheService; - public CachedTasksRepository(TasksRepository tasksRepository, IMemoryCache memoryCache) + /// + /// Initializes a new instance of the class. + /// + /// + /// + public CachedTasksRepository(TasksRepository tasksRepository, IRedisCacheService cacheService) { _tasksRepository = tasksRepository; - _memoryCache = memoryCache; + _cacheService = cacheService; } public async Task> GetAllAsync(string id) { var cacheKey = $"List-{id}-Tasks"; - var cachedTasks = await _memoryCache.GetOrCreateAsync>( - cacheKey, - entry => - { - entry.SetAbsoluteExpiration(TimeSpan.FromMinutes(Constants.TimeSpanByMinutesForCaching)); - return _tasksRepository.GetAllAsync(id); - }); + var cachedTasks = await _cacheService.GetData>(cacheKey); + if (cachedTasks is not null) return cachedTasks; - return cachedTasks ?? []; + var tasks = await _tasksRepository.GetAllAsync(id); + var taskEntities = tasks.ToList(); + await _cacheService.SetData(cacheKey, taskEntities); + return taskEntities; } public async Task GetByIdAsync(Guid id) { var cacheKey = $"Task-{id}"; - var cachedTask = await _memoryCache.GetOrCreateAsync( - cacheKey, - entry => - { - entry.SetAbsoluteExpiration(TimeSpan.FromMinutes(Constants.TimeSpanByMinutesForCaching)); - return _tasksRepository.GetByIdAsync(id); - }); + var cachedTask = await _cacheService.GetData(cacheKey); + if (cachedTask is not null) return cachedTask; - return cachedTask ?? throw new TaskNotFoundException($"The task with id: {id} was not found."); + var task = await _tasksRepository.GetByIdAsync(id); + await _cacheService.SetData(cacheKey, task); + return task; } public async Task AddAsync(AddTaskDto entity) @@ -58,11 +56,9 @@ public async Task AddAsync(AddTaskDto entity) public async Task UpdateAsync(UpdateTaskDto entity) { var updatedTask = await _tasksRepository.UpdateAsync(entity); - var taskEntity = await _tasksRepository.GetByIdAsync(entity.Id); await UpdateAllTasksInCache(taskEntity.ListId.ToString() ?? throw new ArgumentNullException(taskEntity.ListId.ToString(), "The ListId cannot be null.")); - return updatedTask; } @@ -72,9 +68,7 @@ public async Task DeleteAsync(Guid id) { var task = await GetByIdAsync(id); await _tasksRepository.DeleteAsync(id); - - _memoryCache.Remove($"Task-{id}"); - + await _cacheService.RemoveData($"Task-{id}"); await UpdateAllTasksInCache(task.ListId.ToString() ?? throw new ArgumentNullException(task.ListId.ToString(), "The ListId cannot be null.")); } @@ -82,7 +76,9 @@ await UpdateAllTasksInCache(task.ListId.ToString() ?? private async Task UpdateAllTasksInCache(string listId) { var cacheKey = $"List-{listId}-Tasks"; - _memoryCache.Remove(cacheKey); - _memoryCache.CreateEntry(cacheKey).Value = await _tasksRepository.GetAllAsync(listId); + var task = await _tasksRepository.GetAllAsync(listId); + var taskEntities = task.ToList(); + await _cacheService.RemoveData(cacheKey); + await _cacheService.SetData(cacheKey, taskEntities); } } \ No newline at end of file diff --git a/Todo.Infrastructure/Repositories/AccountRepository.cs b/Todo.Infrastructure/Repositories/DB/AccountRepository.cs similarity index 99% rename from Todo.Infrastructure/Repositories/AccountRepository.cs rename to Todo.Infrastructure/Repositories/DB/AccountRepository.cs index 3a7e942..02aaf2a 100644 --- a/Todo.Infrastructure/Repositories/AccountRepository.cs +++ b/Todo.Infrastructure/Repositories/DB/AccountRepository.cs @@ -7,7 +7,7 @@ using Todo.Core.Interfaces; using Task = System.Threading.Tasks.Task; -namespace Todo.Infrastructure.Repositories; +namespace Todo.Infrastructure.Repositories.DB; /// /// AccountService class is used to manage user operations like changing password, updating user information etc. diff --git a/Todo.Infrastructure/Repositories/ListRepository.cs b/Todo.Infrastructure/Repositories/DB/ListRepository.cs similarity index 99% rename from Todo.Infrastructure/Repositories/ListRepository.cs rename to Todo.Infrastructure/Repositories/DB/ListRepository.cs index 6525d15..3c05c7d 100644 --- a/Todo.Infrastructure/Repositories/ListRepository.cs +++ b/Todo.Infrastructure/Repositories/DB/ListRepository.cs @@ -6,7 +6,7 @@ using Todo.Infrastructure.DatabaseContexts; using Task = System.Threading.Tasks.Task; -namespace Todo.Infrastructure.Repositories; +namespace Todo.Infrastructure.Repositories.DB; /// /// A repository for managing the task lists. diff --git a/Todo.Infrastructure/Repositories/RefreshTokenRepository.cs b/Todo.Infrastructure/Repositories/DB/RefreshTokenRepository.cs similarity index 98% rename from Todo.Infrastructure/Repositories/RefreshTokenRepository.cs rename to Todo.Infrastructure/Repositories/DB/RefreshTokenRepository.cs index af87671..46e1b8c 100644 --- a/Todo.Infrastructure/Repositories/RefreshTokenRepository.cs +++ b/Todo.Infrastructure/Repositories/DB/RefreshTokenRepository.cs @@ -5,7 +5,7 @@ using Todo.Infrastructure.DatabaseContexts; using Task = System.Threading.Tasks.Task; -namespace Todo.Infrastructure.Repositories; +namespace Todo.Infrastructure.Repositories.DB; public class RefreshTokenRepository : IRefreshTokenRepository { diff --git a/Todo.Infrastructure/Repositories/TasksRepository.cs b/Todo.Infrastructure/Repositories/DB/TasksRepository.cs similarity index 99% rename from Todo.Infrastructure/Repositories/TasksRepository.cs rename to Todo.Infrastructure/Repositories/DB/TasksRepository.cs index 1a4121c..e543ec7 100644 --- a/Todo.Infrastructure/Repositories/TasksRepository.cs +++ b/Todo.Infrastructure/Repositories/DB/TasksRepository.cs @@ -5,7 +5,7 @@ using Todo.Infrastructure.DatabaseContexts; using Task_Entity = Todo.Core.Entities.Task; -namespace Todo.Infrastructure.Repositories; +namespace Todo.Infrastructure.Repositories.DB; /// /// A class that implements the IRepository interface for the Task entity. diff --git a/Todo.Infrastructure/Services/RedisCachingService.cs b/Todo.Infrastructure/Services/RedisCachingService.cs new file mode 100644 index 0000000..abf2994 --- /dev/null +++ b/Todo.Infrastructure/Services/RedisCachingService.cs @@ -0,0 +1,34 @@ +using System.Text.Json; +using Microsoft.Extensions.Caching.Distributed; +using Todo.Core.Interfaces; +using Todo.Infrastructure.Configurations; + +namespace Todo.Infrastructure.Services; + +public class RedisCachingService(IDistributedCache cache) : IRedisCacheService +{ + public async Task GetData(string key) + { + var data = await cache.GetStringAsync(key); + return string.IsNullOrEmpty(data) ? default : JsonSerializer.Deserialize(data); + } + + public async Task SetData(string key, T data) + { + var options = new DistributedCacheEntryOptions + { + AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(Constants.TimeSpanByMinutesForCaching), + SlidingExpiration = TimeSpan.FromMinutes(Constants.TimeSpanByMinutesForCaching) + }; + await cache.SetStringAsync(key, JsonSerializer.Serialize(data), options); + } + + public async Task UpdateData(string key, T data) + { + await cache.RemoveAsync(key); + await SetData(key, data); + return data; + } + + public async Task RemoveData(string key) => await cache.RemoveAsync(key); +} \ No newline at end of file diff --git a/Todo.Infrastructure/Todo.Infrastructure.csproj b/Todo.Infrastructure/Todo.Infrastructure.csproj index 1510193..ae0a4cb 100644 --- a/Todo.Infrastructure/Todo.Infrastructure.csproj +++ b/Todo.Infrastructure/Todo.Infrastructure.csproj @@ -19,7 +19,9 @@ + + diff --git a/Todo.sln b/Todo.sln index 8fb644b..d249e65 100644 --- a/Todo.sln +++ b/Todo.sln @@ -8,6 +8,8 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{24FC08AC-E3BE-4FEC-9615-F92D133866B8}" ProjectSection(SolutionItems) = preProject docker-compose.yml = docker-compose.yml + Dockerfile = Dockerfile + Jenkinsfile = Jenkinsfile EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Todo.UnitTests", "Todo.UnitTests\Todo.UnitTests.csproj", "{08946D7C-7CEB-4C46-81C1-85AE850F72A7}" diff --git a/docker-compose.yml b/docker-compose.yml index 1f9dea5..fc6e496 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,4 +1,12 @@ services: + cache: + image: redis:alpine + container_name: todo-redis-cache + networks: + - todo-network + ports: + - "6379:6379" + api: build: . image: todo-api:latest @@ -7,6 +15,8 @@ services: - "8070:8080" volumes: - todo-db:/TodoApi/Database + networks: + - todo-network environment: - ASPNETCORE_ENVIRONMENT=Production command: @@ -14,4 +24,9 @@ services: volumes: todo-db: - name: todo-db \ No newline at end of file + name: todo-db + +networks: + todo-network: + driver: bridge + name: todo-network \ No newline at end of file