diff --git a/docker-compose.override.yml b/docker-compose.override.yml index 19c255c6e..3457d8b9f 100644 --- a/docker-compose.override.yml +++ b/docker-compose.override.yml @@ -7,7 +7,12 @@ version: '2' # An external IP or DNS name has to be used (instead localhost and the 10.0.75.1 IP) when testing the Web apps and the Xamarin apps from remote machines/devices using the same WiFi, for instance. services: - + sagamanager: + environment: + - ConnectionString=Server=sql.data;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word + - EventBusConnection=rabbitmq + - GracePeriod=15 #In minutes + basket.api: environment: - ASPNETCORE_ENVIRONMENT=Development diff --git a/docker-compose.vs.debug.yml b/docker-compose.vs.debug.yml index 88ebfc47c..eaa0b6f35 100644 --- a/docker-compose.vs.debug.yml +++ b/docker-compose.vs.debug.yml @@ -120,3 +120,16 @@ services: entrypoint: tail -f /dev/null labels: - "com.microsoft.visualstudio.targetoperatingsystem=linux" + + sagamanager: + image: eshop/sagamanager:dev + build: + args: + source: ${DOCKER_BUILD_SOURCE} + volumes: + - ./src/Services/SagaManager/SagaManager:/app + - ~/.nuget/packages:/root/.nuget/packages:ro + - ~/clrdbg:/clrdbg:ro + entrypoint: tail -f /dev/null + labels: + - "com.microsoft.visualstudio.targetoperatingsystem=linux" diff --git a/docker-compose.vs.release.yml b/docker-compose.vs.release.yml index 9a51a08f5..a0c9d890d 100644 --- a/docker-compose.vs.release.yml +++ b/docker-compose.vs.release.yml @@ -80,3 +80,13 @@ services: entrypoint: tail -f /dev/null labels: - "com.microsoft.visualstudio.targetoperatingsystem=linux" + + sagamanager: + build: + args: + source: ${DOCKER_BUILD_SOURCE} + volumes: + - ~/clrdbg:/clrdbg:ro + entrypoint: tail -f /dev/null + labels: + - "com.microsoft.visualstudio.targetoperatingsystem=linux" diff --git a/docker-compose.yml b/docker-compose.yml index 718bfc5f5..cc134a005 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,6 +1,16 @@ version: '2' + services: + sagamanager: + image: eshop/sagamanager + build: + context: ./src/Services/SagaManager/SagaManager + dockerfile: Dockerfile + depends_on: + - sql.data + - rabbitmq + basket.api: image: eshop/basket.api build: @@ -9,7 +19,6 @@ services: depends_on: - basket.data - identity.api - - rabbitmq catalog.api: image: eshop/catalog.api @@ -35,6 +44,7 @@ services: dockerfile: Dockerfile depends_on: - sql.data + - rabbitmq webspa: image: eshop/webspa diff --git a/eShopOnContainers-ServicesAndWebApps.sln b/eShopOnContainers-ServicesAndWebApps.sln index f5c4c7384..d59b891f6 100644 --- a/eShopOnContainers-ServicesAndWebApps.sln +++ b/eShopOnContainers-ServicesAndWebApps.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.26403.3 +VisualStudioVersion = 15.0.26403.7 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{932D8224-11F6-4D07-B109-DA28AD288A63}" EndProject @@ -78,6 +78,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Payment", "Payment", "{022E EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Payment.API", "src\Services\Payment\Payment.API\Payment.API.csproj", "{1A01AF82-6FCB-464C-B39C-F127AEBD315D}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SagaManager", "SagaManager", "{F38B4FF0-0B49-405A-B1B4-F7A5E3BC4C4E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SagaManager", "src\Services\SagaManager\SagaManager\SagaManager.csproj", "{F6E0F0DD-1400-43C3-B5E0-7CC325728C47}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Ad-Hoc|Any CPU = Ad-Hoc|Any CPU @@ -1004,6 +1008,54 @@ Global {1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Release|x64.Build.0 = Release|Any CPU {1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Release|x86.ActiveCfg = Release|Any CPU {1A01AF82-6FCB-464C-B39C-F127AEBD315D}.Release|x86.Build.0 = Release|Any CPU + {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU + {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU + {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU + {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU + {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU + {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU + {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU + {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU + {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Ad-Hoc|x64.Build.0 = Debug|Any CPU + {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU + {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.AppStore|Any CPU.Build.0 = Debug|Any CPU + {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.AppStore|ARM.ActiveCfg = Debug|Any CPU + {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.AppStore|ARM.Build.0 = Debug|Any CPU + {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.AppStore|iPhone.ActiveCfg = Debug|Any CPU + {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.AppStore|iPhone.Build.0 = Debug|Any CPU + {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU + {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.AppStore|x64.ActiveCfg = Debug|Any CPU + {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.AppStore|x64.Build.0 = Debug|Any CPU + {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.AppStore|x86.ActiveCfg = Debug|Any CPU + {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.AppStore|x86.Build.0 = Debug|Any CPU + {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Debug|ARM.ActiveCfg = Debug|Any CPU + {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Debug|ARM.Build.0 = Debug|Any CPU + {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Debug|iPhone.Build.0 = Debug|Any CPU + {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Debug|x64.ActiveCfg = Debug|Any CPU + {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Debug|x64.Build.0 = Debug|Any CPU + {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Debug|x86.ActiveCfg = Debug|Any CPU + {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Debug|x86.Build.0 = Debug|Any CPU + {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Release|Any CPU.Build.0 = Release|Any CPU + {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Release|ARM.ActiveCfg = Release|Any CPU + {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Release|ARM.Build.0 = Release|Any CPU + {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Release|iPhone.ActiveCfg = Release|Any CPU + {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Release|iPhone.Build.0 = Release|Any CPU + {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Release|x64.ActiveCfg = Release|Any CPU + {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Release|x64.Build.0 = Release|Any CPU + {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Release|x86.ActiveCfg = Release|Any CPU + {F6E0F0DD-1400-43C3-B5E0-7CC325728C47}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1041,5 +1093,7 @@ Global {D1C47FF1-91F1-4CAF-9ABB-AD642B821502} = {FBF43D93-F2E7-4FF8-B4AB-186895949B88} {022E145D-1593-47EE-9608-8E323D3C63F5} = {91CF7717-08AB-4E65-B10E-0B426F01E2E8} {1A01AF82-6FCB-464C-B39C-F127AEBD315D} = {022E145D-1593-47EE-9608-8E323D3C63F5} + {F38B4FF0-0B49-405A-B1B4-F7A5E3BC4C4E} = {91CF7717-08AB-4E65-B10E-0B426F01E2E8} + {F6E0F0DD-1400-43C3-B5E0-7CC325728C47} = {F38B4FF0-0B49-405A-B1B4-F7A5E3BC4C4E} EndGlobalSection EndGlobal diff --git a/src/Services/Ordering/Ordering.API/Application/IntegrationCommands/Commands/ConfirmGracePeriodCommandMsg.cs b/src/Services/Ordering/Ordering.API/Application/IntegrationCommands/Commands/ConfirmGracePeriodCommandMsg.cs index a0767459e..f9d8b8923 100644 --- a/src/Services/Ordering/Ordering.API/Application/IntegrationCommands/Commands/ConfirmGracePeriodCommandMsg.cs +++ b/src/Services/Ordering/Ordering.API/Application/IntegrationCommands/Commands/ConfirmGracePeriodCommandMsg.cs @@ -1,15 +1,12 @@ using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; namespace Ordering.API.Application.IntegrationCommands.Commands { public class ConfirmGracePeriodCommandMsg : IntegrationEvent { - public int OrderNumber { get; private set; } + public int OrderId { get; } - //TODO: message should change to Integration command type once command bus is implemented + public ConfirmGracePeriodCommandMsg(int orderId) => + OrderId = orderId; } } diff --git a/src/Services/Ordering/Ordering.API/Application/Sagas/OrderProcessSaga.cs b/src/Services/Ordering/Ordering.API/Application/Sagas/OrderProcessSaga.cs index 32df5b327..c31c35e6d 100644 --- a/src/Services/Ordering/Ordering.API/Application/Sagas/OrderProcessSaga.cs +++ b/src/Services/Ordering/Ordering.API/Application/Sagas/OrderProcessSaga.cs @@ -10,6 +10,7 @@ using Ordering.API.Application.IntegrationCommands.Commands; using Ordering.Domain.Exceptions; using System; using System.Threading.Tasks; +using Ordering.API.Application.IntegrationEvents.Events; namespace Ordering.API.Application.Sagas { @@ -73,13 +74,17 @@ namespace Ordering.API.Application.Sagas /// public async Task Handle(ConfirmGracePeriodCommandMsg command) { - var orderSaga = FindSagaById(command.OrderNumber); + var orderSaga = FindSagaById(command.OrderId); CheckValidSagaId(orderSaga); // TODO: This handler should change to Integration command handler type once command bus is implemented - // TODO: If order status is not cancelled, change state to awaitingValidation and - // send ConfirmOrderStockCommandMsg to Inventory api + // send ConfirmOrderStockCommandMsg to Inventory api + if (orderSaga.OrderStatus == OrderStatus.Submitted) + { + + } + } diff --git a/src/Services/Ordering/Ordering.API/Ordering.API.csproj b/src/Services/Ordering/Ordering.API/Ordering.API.csproj index ba35d75e2..445f93ad8 100644 --- a/src/Services/Ordering/Ordering.API/Ordering.API.csproj +++ b/src/Services/Ordering/Ordering.API/Ordering.API.csproj @@ -13,6 +13,13 @@ ..\..\..\..\docker-compose.dcproj + + + + + + + PreserveNewest @@ -80,7 +87,6 @@ - diff --git a/src/Services/Ordering/Ordering.API/Startup.cs b/src/Services/Ordering/Ordering.API/Startup.cs index 4ecb5231c..82bbf6fd4 100644 --- a/src/Services/Ordering/Ordering.API/Startup.cs +++ b/src/Services/Ordering/Ordering.API/Startup.cs @@ -1,4 +1,6 @@ -namespace Microsoft.eShopOnContainers.Services.Ordering.API + + +namespace Microsoft.eShopOnContainers.Services.Ordering.API { using AspNetCore.Http; using Autofac; @@ -21,6 +23,9 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.HealthChecks; using Microsoft.Extensions.Logging; + using Ordering.API.Application.Commands; + using Ordering.API.Application.IntegrationCommands.Commands; + using Ordering.API.Application.IntegrationEvents.Events; using Ordering.Infrastructure; using RabbitMQ.Client; using System; @@ -157,6 +162,8 @@ .UseSqlServer(Configuration["ConnectionString"], b => b.MigrationsAssembly("Ordering.API")) .Options); integrationEventLogContext.Database.Migrate(); + + ConfigureEventBus(app); } protected virtual void ConfigureAuth(IApplicationBuilder app) @@ -169,5 +176,16 @@ RequireHttpsMetadata = false }); } + + protected virtual void ConfigureEventBus(IApplicationBuilder app) + { + var confirmGracePeriodHandler = app.ApplicationServices + .GetService>(); + + var eventBus = app.ApplicationServices + .GetRequiredService(); + + eventBus.Subscribe(confirmGracePeriodHandler); + } } } diff --git a/src/Services/SagaManager/SagaManager/.dockerignore b/src/Services/SagaManager/SagaManager/.dockerignore new file mode 100644 index 000000000..d8f8175f6 --- /dev/null +++ b/src/Services/SagaManager/SagaManager/.dockerignore @@ -0,0 +1,3 @@ +* +!obj/Docker/publish/* +!obj/Docker/empty/ diff --git a/src/Services/SagaManager/SagaManager/Dockerfile b/src/Services/SagaManager/SagaManager/Dockerfile new file mode 100644 index 000000000..f8adb603a --- /dev/null +++ b/src/Services/SagaManager/SagaManager/Dockerfile @@ -0,0 +1,5 @@ +FROM microsoft/dotnet:1.1-runtime +ARG source +WORKDIR /app +COPY ${source:-obj/Docker/publish} . +ENTRYPOINT ["dotnet", "SagaManager.dll"] \ No newline at end of file diff --git a/src/Services/SagaManager/SagaManager/IntegrationEvents/ConfirmGracePeriodEvent.cs b/src/Services/SagaManager/SagaManager/IntegrationEvents/ConfirmGracePeriodEvent.cs new file mode 100644 index 000000000..36f88c9be --- /dev/null +++ b/src/Services/SagaManager/SagaManager/IntegrationEvents/ConfirmGracePeriodEvent.cs @@ -0,0 +1,16 @@ +namespace SagaManager.IntegrationEvents +{ + using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; + using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; + using System; + + public class ConfirmGracePeriodEvent : IConfirmGracePeriodEvent + { + private readonly IEventBus _eventBus; + + public ConfirmGracePeriodEvent(IEventBus eventBus) => + _eventBus = eventBus ?? throw new ArgumentNullException(nameof(eventBus)); + + public void PublishThroughEventBus(IntegrationEvent evt) => _eventBus.Publish(evt); + } +} \ No newline at end of file diff --git a/src/Services/SagaManager/SagaManager/IntegrationEvents/Events/ConfirmGracePeriodIntegrationEvent.cs b/src/Services/SagaManager/SagaManager/IntegrationEvents/Events/ConfirmGracePeriodIntegrationEvent.cs new file mode 100644 index 000000000..680328301 --- /dev/null +++ b/src/Services/SagaManager/SagaManager/IntegrationEvents/Events/ConfirmGracePeriodIntegrationEvent.cs @@ -0,0 +1,14 @@ +namespace SagaManager.IntegrationEvents.Events +{ + using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; + + // Integration Events notes: + // An Event is “something that has happened in the past”, therefore its name has to be + // An Integration Event is an event that can cause side effects to other microsrvices, Bounded-Contexts or external systems. + public class ConfirmGracePeriodIntegrationEvent : IntegrationEvent + { + public int OrderId { get;} + + public ConfirmGracePeriodIntegrationEvent(int orderId) => OrderId = orderId; + } +} diff --git a/src/Services/SagaManager/SagaManager/IntegrationEvents/IConfirmGracePeriodEvent.cs b/src/Services/SagaManager/SagaManager/IntegrationEvents/IConfirmGracePeriodEvent.cs new file mode 100644 index 000000000..236860db2 --- /dev/null +++ b/src/Services/SagaManager/SagaManager/IntegrationEvents/IConfirmGracePeriodEvent.cs @@ -0,0 +1,9 @@ +namespace SagaManager.IntegrationEvents +{ + using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; + + public interface IConfirmGracePeriodEvent + { + void PublishThroughEventBus(IntegrationEvent evt); + } +} \ No newline at end of file diff --git a/src/Services/SagaManager/SagaManager/Program.cs b/src/Services/SagaManager/SagaManager/Program.cs new file mode 100644 index 000000000..d76a8a080 --- /dev/null +++ b/src/Services/SagaManager/SagaManager/Program.cs @@ -0,0 +1,65 @@ +using SagaManager.IntegrationEvents; + +namespace SagaManager +{ + using System.IO; + using System; + using Microsoft.Extensions.Configuration; + using Microsoft.Extensions.DependencyInjection; + using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; + using Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ; + using Microsoft.Extensions.Logging; + using Microsoft.Extensions.Options; + using RabbitMQ.Client; + using Services; + + public class Program + { + public static IConfigurationRoot Configuration { get; set; } + + public static void Main(string[] args) + { + var builder = new ConfigurationBuilder() + .SetBasePath(Directory.GetCurrentDirectory()) + .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) + .AddEnvironmentVariables(); + + Configuration = builder.Build(); + + var serviceProvider = new ServiceCollection() + .AddLogging() + .AddOptions() + .Configure(Configuration) + .AddSingleton() + .AddSingleton() + .AddSingleton(sp => + { + var settings = sp.GetRequiredService>().Value; + var logger = sp.GetRequiredService>(); + var factory = new ConnectionFactory() + { + HostName = settings.EventBusConnection + }; + + return new DefaultRabbitMQPersisterConnection(factory, logger); + }) + .AddSingleton() + .BuildServiceProvider(); + + //configure console logging + serviceProvider + .GetService() + .AddConsole(Configuration.GetSection("Logging")) + .AddConsole(LogLevel.Debug); + + var sagaManagerService = serviceProvider + .GetRequiredService(); + + while (true) + { + sagaManagerService.CheckFinishedGracePeriodOrders(); + System.Threading.Thread.Sleep(30000); + } + } + } +} \ No newline at end of file diff --git a/src/Services/SagaManager/SagaManager/SagaManager.csproj b/src/Services/SagaManager/SagaManager/SagaManager.csproj new file mode 100644 index 000000000..47b8b58c2 --- /dev/null +++ b/src/Services/SagaManager/SagaManager/SagaManager.csproj @@ -0,0 +1,32 @@ + + + + Exe + netcoreapp1.1 + + + + + + + + + + + + + + + + + + + + + + + Dockerfile + + + + \ No newline at end of file diff --git a/src/Services/SagaManager/SagaManager/SagaManagerSettings.cs b/src/Services/SagaManager/SagaManager/SagaManagerSettings.cs new file mode 100644 index 000000000..ab9184b8a --- /dev/null +++ b/src/Services/SagaManager/SagaManager/SagaManagerSettings.cs @@ -0,0 +1,11 @@ +namespace SagaManager +{ + public class SagaManagerSettings + { + public string ConnectionString { get; set; } + + public string EventBusConnection { get; set; } + + public int GracePeriod { get; set; } + } +} \ No newline at end of file diff --git a/src/Services/SagaManager/SagaManager/Services/ISagaManagerService.cs b/src/Services/SagaManager/SagaManager/Services/ISagaManagerService.cs new file mode 100644 index 000000000..dc027b29c --- /dev/null +++ b/src/Services/SagaManager/SagaManager/Services/ISagaManagerService.cs @@ -0,0 +1,7 @@ +namespace SagaManager.Services +{ + public interface ISagaManagerService + { + void CheckFinishedGracePeriodOrders(); + } +} \ No newline at end of file diff --git a/src/Services/SagaManager/SagaManager/Services/SagaManagerService.cs b/src/Services/SagaManager/SagaManager/Services/SagaManagerService.cs new file mode 100644 index 000000000..991e62029 --- /dev/null +++ b/src/Services/SagaManager/SagaManager/Services/SagaManagerService.cs @@ -0,0 +1,59 @@ +namespace SagaManager.Services +{ + using System.Collections.Generic; + using System.Data.SqlClient; + using Microsoft.Extensions.Options; + using Dapper; + using IntegrationEvents; + using IntegrationEvents.Events; + + public class SagaManagerService : ISagaManagerService + { + private readonly SagaManagerSettings _settings; + private readonly IConfirmGracePeriodEvent _confirmGracePeriodEvent; + + public SagaManagerService(IOptions settings, + IConfirmGracePeriodEvent confirmGracePeriodEvent) + { + _settings = settings.Value; + _confirmGracePeriodEvent = confirmGracePeriodEvent; + } + + public void CheckFinishedGracePeriodOrders() + { + var orderIds = GetFinishedGracePeriodOrders(); + + foreach (var orderId in orderIds) + { + Publish(orderId); + } + } + + private IEnumerable GetFinishedGracePeriodOrders() + { + IEnumerable orderIds = new List(); + using (var conn = new SqlConnection(_settings.ConnectionString)) + { + if (conn != null) + { + conn.Open(); + orderIds = conn.Query( + @"SELECT Id FROM [Microsoft.eShopOnContainers.Services.OrderingDb].[ordering].[orders] + WHERE DATEDIFF(hour, [OrderDate], GETDATE()) >= @GracePeriod + AND [OrderStatusId] = 1", + new { GracePeriod = _settings.GracePeriod }); + } + } + + return orderIds; + } + + private void Publish(int orderId) + { + var confirmGracePeriodEvent = new ConfirmGracePeriodIntegrationEvent(orderId); + + // Publish through the Event Bus and mark the saved event as published + _confirmGracePeriodEvent.PublishThroughEventBus(confirmGracePeriodEvent); + } + } +} \ No newline at end of file diff --git a/src/Services/SagaManager/SagaManager/appsettings.json b/src/Services/SagaManager/SagaManager/appsettings.json new file mode 100644 index 000000000..19c7b8b28 --- /dev/null +++ b/src/Services/SagaManager/SagaManager/appsettings.json @@ -0,0 +1,11 @@ +{ + "Logging": { + "IncludeScopes": false, + "LogLevel": { + "Default": "Debug", + "System": "Information", + "Microsoft": "Information" + } + }, + "ConnectionString": "Server=sql.data;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word" +}