Implemented HostedService in different service
This commit is contained in:
parent
e869b67c6d
commit
025ab0e14c
@ -83,6 +83,24 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- "5102:80"
|
- "5102:80"
|
||||||
|
|
||||||
|
ordering.backgroundtasks:
|
||||||
|
environment:
|
||||||
|
- ASPNETCORE_ENVIRONMENT=Development
|
||||||
|
- ASPNETCORE_URLS=http://0.0.0.0:80
|
||||||
|
- ConnectionString=${ESHOP_AZURE_ORDERING_DB:-Server=sql.data;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word}
|
||||||
|
- EventBusConnection=${ESHOP_AZURE_SERVICE_BUS:-rabbitmq}
|
||||||
|
- EventBusUserName=${ESHOP_SERVICE_BUS_USERNAME}
|
||||||
|
- EventBusPassword=${ESHOP_SERVICE_BUS_PASSWORD}
|
||||||
|
- UseCustomizationData=True
|
||||||
|
- AzureServiceBusEnabled=False
|
||||||
|
- CheckUpdateTime=30000
|
||||||
|
- GracePeriodTime=1
|
||||||
|
- ApplicationInsights__InstrumentationKey=${INSTRUMENTATION_KEY}
|
||||||
|
- OrchestratorType=${ORCHESTRATOR_TYPE}
|
||||||
|
- UseLoadTest=${USE_LOADTEST:-False}
|
||||||
|
ports:
|
||||||
|
- "5111:80"
|
||||||
|
|
||||||
marketing.api:
|
marketing.api:
|
||||||
environment:
|
environment:
|
||||||
- ASPNETCORE_ENVIRONMENT=Development
|
- ASPNETCORE_ENVIRONMENT=Development
|
||||||
@ -219,4 +237,5 @@ services:
|
|||||||
rabbitmq:
|
rabbitmq:
|
||||||
ports:
|
ports:
|
||||||
- "15672:15672"
|
- "15672:15672"
|
||||||
- "5672:5672"
|
- "5672:5672"
|
||||||
|
|
||||||
|
@ -90,6 +90,24 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- "5102:80"
|
- "5102:80"
|
||||||
|
|
||||||
|
ordering.backgroundtasks:
|
||||||
|
environment:
|
||||||
|
- ASPNETCORE_ENVIRONMENT=Development
|
||||||
|
- ASPNETCORE_URLS=http://0.0.0.0:80
|
||||||
|
- ConnectionString=${ESHOP_AZURE_ORDERING_DB:-Server=sql.data;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word}
|
||||||
|
- EventBusConnection=${ESHOP_AZURE_SERVICE_BUS:-rabbitmq}
|
||||||
|
- EventBusUserName=${ESHOP_SERVICE_BUS_USERNAME}
|
||||||
|
- EventBusPassword=${ESHOP_SERVICE_BUS_PASSWORD}
|
||||||
|
- UseCustomizationData=True
|
||||||
|
- AzureServiceBusEnabled=False
|
||||||
|
- CheckUpdateTime=30000
|
||||||
|
- GracePeriodTime=1
|
||||||
|
- ApplicationInsights__InstrumentationKey=${INSTRUMENTATION_KEY}
|
||||||
|
- OrchestratorType=${ORCHESTRATOR_TYPE}
|
||||||
|
- UseLoadTest=${USE_LOADTEST:-False}
|
||||||
|
ports:
|
||||||
|
- "5111:80"
|
||||||
|
|
||||||
marketing.api:
|
marketing.api:
|
||||||
environment:
|
environment:
|
||||||
- ASPNETCORE_ENVIRONMENT=Development
|
- ASPNETCORE_ENVIRONMENT=Development
|
||||||
|
@ -38,6 +38,15 @@ services:
|
|||||||
- sql.data
|
- sql.data
|
||||||
- rabbitmq
|
- rabbitmq
|
||||||
|
|
||||||
|
ordering.backgroundtasks:
|
||||||
|
image: eshop/ordering.backgroundtasks:${TAG:-latest}
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: src/Services/Ordering/Ordering.BackgroundTasks/Dockerfile
|
||||||
|
depends_on:
|
||||||
|
- sql.data
|
||||||
|
- rabbitmq
|
||||||
|
|
||||||
marketing.api:
|
marketing.api:
|
||||||
image: eshop/marketing.api:${TAG:-latest}
|
image: eshop/marketing.api:${TAG:-latest}
|
||||||
build:
|
build:
|
||||||
@ -106,4 +115,4 @@ services:
|
|||||||
image: redis:alpine
|
image: redis:alpine
|
||||||
|
|
||||||
rabbitmq:
|
rabbitmq:
|
||||||
image: rabbitmq:3-management-alpine
|
image: rabbitmq:3-management-alpine
|
@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio 15
|
# Visual Studio 15
|
||||||
VisualStudioVersion = 15.0.27004.2009
|
VisualStudioVersion = 15.0.27130.2024
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{E53339B2-1760-4266-BCC7-CA923CBCF16C}") = "docker-compose", "docker-compose.dcproj", "{FEA0C318-FFED-4D39-8781-265718CA43DD}"
|
Project("{E53339B2-1760-4266-BCC7-CA923CBCF16C}") = "docker-compose", "docker-compose.dcproj", "{FEA0C318-FFED-4D39-8781-265718CA43DD}"
|
||||||
EndProject
|
EndProject
|
||||||
@ -97,6 +97,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "WebHost", "WebHost", "{1815
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebHost.Customization", "src\BuildingBlocks\WebHostCustomization\WebHost.Customization\WebHost.Customization.csproj", "{15F4B3AA-89B6-4A0D-9051-414305974781}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebHost.Customization", "src\BuildingBlocks\WebHostCustomization\WebHost.Customization\WebHost.Customization.csproj", "{15F4B3AA-89B6-4A0D-9051-414305974781}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ordering.BackgroundTasks", "src\Services\Ordering\Ordering.BackgroundTasks\Ordering.BackgroundTasks.csproj", "{2FF56999-0266-48B2-ACC1-FEBC482A5105}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Ad-Hoc|Any CPU = Ad-Hoc|Any CPU
|
Ad-Hoc|Any CPU = Ad-Hoc|Any CPU
|
||||||
@ -1311,6 +1313,54 @@ Global
|
|||||||
{15F4B3AA-89B6-4A0D-9051-414305974781}.Release|x64.Build.0 = Release|Any CPU
|
{15F4B3AA-89B6-4A0D-9051-414305974781}.Release|x64.Build.0 = Release|Any CPU
|
||||||
{15F4B3AA-89B6-4A0D-9051-414305974781}.Release|x86.ActiveCfg = Release|Any CPU
|
{15F4B3AA-89B6-4A0D-9051-414305974781}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
{15F4B3AA-89B6-4A0D-9051-414305974781}.Release|x86.Build.0 = Release|Any CPU
|
{15F4B3AA-89B6-4A0D-9051-414305974781}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{2FF56999-0266-48B2-ACC1-FEBC482A5105}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{2FF56999-0266-48B2-ACC1-FEBC482A5105}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{2FF56999-0266-48B2-ACC1-FEBC482A5105}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
|
||||||
|
{2FF56999-0266-48B2-ACC1-FEBC482A5105}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU
|
||||||
|
{2FF56999-0266-48B2-ACC1-FEBC482A5105}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
|
||||||
|
{2FF56999-0266-48B2-ACC1-FEBC482A5105}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
|
||||||
|
{2FF56999-0266-48B2-ACC1-FEBC482A5105}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||||
|
{2FF56999-0266-48B2-ACC1-FEBC482A5105}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||||
|
{2FF56999-0266-48B2-ACC1-FEBC482A5105}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{2FF56999-0266-48B2-ACC1-FEBC482A5105}.Ad-Hoc|x64.Build.0 = Debug|Any CPU
|
||||||
|
{2FF56999-0266-48B2-ACC1-FEBC482A5105}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{2FF56999-0266-48B2-ACC1-FEBC482A5105}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
|
||||||
|
{2FF56999-0266-48B2-ACC1-FEBC482A5105}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{2FF56999-0266-48B2-ACC1-FEBC482A5105}.AppStore|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{2FF56999-0266-48B2-ACC1-FEBC482A5105}.AppStore|ARM.ActiveCfg = Debug|Any CPU
|
||||||
|
{2FF56999-0266-48B2-ACC1-FEBC482A5105}.AppStore|ARM.Build.0 = Debug|Any CPU
|
||||||
|
{2FF56999-0266-48B2-ACC1-FEBC482A5105}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
|
||||||
|
{2FF56999-0266-48B2-ACC1-FEBC482A5105}.AppStore|iPhone.Build.0 = Debug|Any CPU
|
||||||
|
{2FF56999-0266-48B2-ACC1-FEBC482A5105}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||||
|
{2FF56999-0266-48B2-ACC1-FEBC482A5105}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||||
|
{2FF56999-0266-48B2-ACC1-FEBC482A5105}.AppStore|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{2FF56999-0266-48B2-ACC1-FEBC482A5105}.AppStore|x64.Build.0 = Debug|Any CPU
|
||||||
|
{2FF56999-0266-48B2-ACC1-FEBC482A5105}.AppStore|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{2FF56999-0266-48B2-ACC1-FEBC482A5105}.AppStore|x86.Build.0 = Debug|Any CPU
|
||||||
|
{2FF56999-0266-48B2-ACC1-FEBC482A5105}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{2FF56999-0266-48B2-ACC1-FEBC482A5105}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{2FF56999-0266-48B2-ACC1-FEBC482A5105}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||||
|
{2FF56999-0266-48B2-ACC1-FEBC482A5105}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||||
|
{2FF56999-0266-48B2-ACC1-FEBC482A5105}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
||||||
|
{2FF56999-0266-48B2-ACC1-FEBC482A5105}.Debug|iPhone.Build.0 = Debug|Any CPU
|
||||||
|
{2FF56999-0266-48B2-ACC1-FEBC482A5105}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||||
|
{2FF56999-0266-48B2-ACC1-FEBC482A5105}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||||
|
{2FF56999-0266-48B2-ACC1-FEBC482A5105}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{2FF56999-0266-48B2-ACC1-FEBC482A5105}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{2FF56999-0266-48B2-ACC1-FEBC482A5105}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{2FF56999-0266-48B2-ACC1-FEBC482A5105}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{2FF56999-0266-48B2-ACC1-FEBC482A5105}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{2FF56999-0266-48B2-ACC1-FEBC482A5105}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{2FF56999-0266-48B2-ACC1-FEBC482A5105}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||||
|
{2FF56999-0266-48B2-ACC1-FEBC482A5105}.Release|ARM.Build.0 = Release|Any CPU
|
||||||
|
{2FF56999-0266-48B2-ACC1-FEBC482A5105}.Release|iPhone.ActiveCfg = Release|Any CPU
|
||||||
|
{2FF56999-0266-48B2-ACC1-FEBC482A5105}.Release|iPhone.Build.0 = Release|Any CPU
|
||||||
|
{2FF56999-0266-48B2-ACC1-FEBC482A5105}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||||
|
{2FF56999-0266-48B2-ACC1-FEBC482A5105}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||||
|
{2FF56999-0266-48B2-ACC1-FEBC482A5105}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{2FF56999-0266-48B2-ACC1-FEBC482A5105}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{2FF56999-0266-48B2-ACC1-FEBC482A5105}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{2FF56999-0266-48B2-ACC1-FEBC482A5105}.Release|x86.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
@ -1357,6 +1407,7 @@ Global
|
|||||||
{969E793C-C413-490E-9C9D-B2B46DA5AF32} = {EF0337F2-ED00-4643-89FD-EE10863F1870}
|
{969E793C-C413-490E-9C9D-B2B46DA5AF32} = {EF0337F2-ED00-4643-89FD-EE10863F1870}
|
||||||
{1815B651-941C-466B-AE33-D1D7EEB8F77F} = {DB0EFB20-B024-4E5E-A75C-52143C131D25}
|
{1815B651-941C-466B-AE33-D1D7EEB8F77F} = {DB0EFB20-B024-4E5E-A75C-52143C131D25}
|
||||||
{15F4B3AA-89B6-4A0D-9051-414305974781} = {1815B651-941C-466B-AE33-D1D7EEB8F77F}
|
{15F4B3AA-89B6-4A0D-9051-414305974781} = {1815B651-941C-466B-AE33-D1D7EEB8F77F}
|
||||||
|
{2FF56999-0266-48B2-ACC1-FEBC482A5105} = {0BD0DB92-2D98-44D9-9AC0-C59186D59B0B}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
SolutionGuid = {25728519-5F0F-4973-8A64-0A81EB4EA8D9}
|
SolutionGuid = {25728519-5F0F-4973-8A64-0A81EB4EA8D9}
|
||||||
|
@ -92,9 +92,13 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ
|
|||||||
|
|
||||||
policy.Execute(() =>
|
policy.Execute(() =>
|
||||||
{
|
{
|
||||||
|
var properties = channel.CreateBasicProperties();
|
||||||
|
properties.DeliveryMode = 2; // persistent
|
||||||
|
|
||||||
channel.BasicPublish(exchange: BROKER_NAME,
|
channel.BasicPublish(exchange: BROKER_NAME,
|
||||||
routingKey: eventName,
|
routingKey: eventName,
|
||||||
basicProperties: null,
|
mandatory:true,
|
||||||
|
basicProperties: properties,
|
||||||
body: body);
|
body: body);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -184,6 +188,8 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ
|
|||||||
var message = Encoding.UTF8.GetString(ea.Body);
|
var message = Encoding.UTF8.GetString(ea.Body);
|
||||||
|
|
||||||
await ProcessEvent(eventName, message);
|
await ProcessEvent(eventName, message);
|
||||||
|
|
||||||
|
channel.BasicAck(ea.DeliveryTag,multiple:false);
|
||||||
};
|
};
|
||||||
|
|
||||||
channel.BasicConsume(queue: _queueName,
|
channel.BasicConsume(queue: _queueName,
|
||||||
|
@ -16,68 +16,68 @@ namespace Ordering.API.Infrastructure.HostedServices
|
|||||||
/// https://github.com/aspnet/Hosting/blob/712c992ca827576c05923e6a134ca0bec87af4df/src/Microsoft.Extensions.Hosting.Abstractions/BackgroundService.cs
|
/// https://github.com/aspnet/Hosting/blob/712c992ca827576c05923e6a134ca0bec87af4df/src/Microsoft.Extensions.Hosting.Abstractions/BackgroundService.cs
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class BackgroundService : IHostedService, IDisposable
|
//public abstract class BackgroundService : IHostedService, IDisposable
|
||||||
{
|
//{
|
||||||
private Task _executingTask;
|
// private Task _executingTask;
|
||||||
private readonly CancellationTokenSource _stoppingCts = new CancellationTokenSource();
|
// private readonly CancellationTokenSource _stoppingCts = new CancellationTokenSource();
|
||||||
|
|
||||||
/// <summary>
|
// /// <summary>
|
||||||
/// This method is called when the <see cref="IHostedService"/> starts. The implementation should return a task that represents
|
// /// This method is called when the <see cref="IHostedService"/> starts. The implementation should return a task that represents
|
||||||
/// the lifetime of the long running operation(s) being performed.
|
// /// the lifetime of the long running operation(s) being performed.
|
||||||
/// </summary>
|
// /// </summary>
|
||||||
/// <param name="stoppingToken">Triggered when <see cref="IHostedService.StopAsync(CancellationToken)"/> is called.</param>
|
// /// <param name="stoppingToken">Triggered when <see cref="IHostedService.StopAsync(CancellationToken)"/> is called.</param>
|
||||||
/// <returns>A <see cref="Task"/> that represents the long running operations.</returns>
|
// /// <returns>A <see cref="Task"/> that represents the long running operations.</returns>
|
||||||
protected abstract Task ExecuteAsync(CancellationToken stoppingToken);
|
// protected abstract Task ExecuteAsync(CancellationToken stoppingToken);
|
||||||
|
|
||||||
/// <summary>
|
// /// <summary>
|
||||||
/// Triggered when the application host is ready to start the service.
|
// /// Triggered when the application host is ready to start the service.
|
||||||
/// </summary>
|
// /// </summary>
|
||||||
/// <param name="cancellationToken">Indicates that the start process has been aborted.</param>
|
// /// <param name="cancellationToken">Indicates that the start process has been aborted.</param>
|
||||||
public virtual Task StartAsync(CancellationToken cancellationToken)
|
// public virtual Task StartAsync(CancellationToken cancellationToken)
|
||||||
{
|
// {
|
||||||
// Store the task we're executing
|
// // Store the task we're executing
|
||||||
_executingTask = ExecuteAsync(_stoppingCts.Token);
|
// _executingTask = ExecuteAsync(_stoppingCts.Token);
|
||||||
|
|
||||||
// If the task is completed then return it, this will bubble cancellation and failure to the caller
|
// // If the task is completed then return it, this will bubble cancellation and failure to the caller
|
||||||
if (_executingTask.IsCompleted)
|
// if (_executingTask.IsCompleted)
|
||||||
{
|
// {
|
||||||
return _executingTask;
|
// return _executingTask;
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Otherwise it's running
|
// // Otherwise it's running
|
||||||
return Task.CompletedTask;
|
// return Task.CompletedTask;
|
||||||
}
|
// }
|
||||||
|
|
||||||
/// <summary>
|
// /// <summary>
|
||||||
/// Triggered when the application host is performing a graceful shutdown.
|
// /// Triggered when the application host is performing a graceful shutdown.
|
||||||
/// </summary>
|
// /// </summary>
|
||||||
/// <param name="cancellationToken">Indicates that the shutdown process should no longer be graceful.</param>
|
// /// <param name="cancellationToken">Indicates that the shutdown process should no longer be graceful.</param>
|
||||||
public virtual async Task StopAsync(CancellationToken cancellationToken)
|
// public virtual async Task StopAsync(CancellationToken cancellationToken)
|
||||||
{
|
// {
|
||||||
// Stop called without start
|
// // Stop called without start
|
||||||
if (_executingTask == null)
|
// if (_executingTask == null)
|
||||||
{
|
// {
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
|
||||||
try
|
// try
|
||||||
{
|
// {
|
||||||
// Signal cancellation to the executing method
|
// // Signal cancellation to the executing method
|
||||||
_stoppingCts.Cancel();
|
// _stoppingCts.Cancel();
|
||||||
}
|
// }
|
||||||
finally
|
// finally
|
||||||
{
|
// {
|
||||||
// Wait until the task completes or the stop token triggers
|
// // Wait until the task completes or the stop token triggers
|
||||||
await Task.WhenAny(_executingTask, Task.Delay(Timeout.Infinite, cancellationToken));
|
// await Task.WhenAny(_executingTask, Task.Delay(Timeout.Infinite, cancellationToken));
|
||||||
}
|
// }
|
||||||
|
|
||||||
}
|
// }
|
||||||
|
|
||||||
public virtual void Dispose()
|
// public virtual void Dispose()
|
||||||
{
|
// {
|
||||||
_stoppingCts.Cancel();
|
// _stoppingCts.Cancel();
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -12,79 +12,79 @@
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
public class GracePeriodManagerService : BackgroundService
|
//public class GracePeriodManagerService : BackgroundService
|
||||||
{
|
//{
|
||||||
private readonly OrderingSettings _settings;
|
// private readonly OrderingSettings _settings;
|
||||||
private readonly ILogger<GracePeriodManagerService> _logger;
|
// private readonly ILogger<GracePeriodManagerService> _logger;
|
||||||
private readonly IEventBus _eventBus;
|
// private readonly IEventBus _eventBus;
|
||||||
|
|
||||||
public GracePeriodManagerService(IOptions<OrderingSettings> settings,
|
// public GracePeriodManagerService(IOptions<OrderingSettings> settings,
|
||||||
IEventBus eventBus,
|
// IEventBus eventBus,
|
||||||
ILogger<GracePeriodManagerService> logger)
|
// ILogger<GracePeriodManagerService> logger)
|
||||||
{
|
// {
|
||||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
// _logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||||
_eventBus = eventBus ?? throw new ArgumentNullException(nameof(eventBus));
|
// _eventBus = eventBus ?? throw new ArgumentNullException(nameof(eventBus));
|
||||||
_settings = settings?.Value ?? throw new ArgumentNullException(nameof(settings));
|
// _settings = settings?.Value ?? throw new ArgumentNullException(nameof(settings));
|
||||||
}
|
// }
|
||||||
|
|
||||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
// protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||||
{
|
// {
|
||||||
_logger.LogDebug($"GracePeriod background task is starting.");
|
// _logger.LogDebug($"GracePeriod background task is starting.");
|
||||||
|
|
||||||
stoppingToken.Register(() => _logger.LogDebug($"#1 GracePeriod background task is stopping."));
|
// stoppingToken.Register(() => _logger.LogDebug($"#1 GracePeriod background task is stopping."));
|
||||||
|
|
||||||
while (!stoppingToken.IsCancellationRequested)
|
// while (!stoppingToken.IsCancellationRequested)
|
||||||
{
|
// {
|
||||||
_logger.LogDebug($"GracePeriod background task is doing background work.");
|
// _logger.LogDebug($"GracePeriod background task is doing background work.");
|
||||||
|
|
||||||
CheckConfirmedGracePeriodOrders();
|
// CheckConfirmedGracePeriodOrders();
|
||||||
|
|
||||||
await Task.Delay(_settings.CheckUpdateTime, stoppingToken);
|
// await Task.Delay(_settings.CheckUpdateTime, stoppingToken);
|
||||||
|
|
||||||
continue;
|
// continue;
|
||||||
}
|
// }
|
||||||
|
|
||||||
_logger.LogDebug($"GracePeriod background task is stopping.");
|
// _logger.LogDebug($"GracePeriod background task is stopping.");
|
||||||
|
|
||||||
}
|
// }
|
||||||
|
|
||||||
private void CheckConfirmedGracePeriodOrders()
|
// private void CheckConfirmedGracePeriodOrders()
|
||||||
{
|
// {
|
||||||
_logger.LogDebug($"Checking confirmed grace period orders");
|
// _logger.LogDebug($"Checking confirmed grace period orders");
|
||||||
|
|
||||||
var orderIds = GetConfirmedGracePeriodOrders();
|
// var orderIds = GetConfirmedGracePeriodOrders();
|
||||||
|
|
||||||
_logger.LogDebug($"GracePeriod sent a .");
|
// _logger.LogDebug($"GracePeriod sent a .");
|
||||||
foreach (var orderId in orderIds)
|
// foreach (var orderId in orderIds)
|
||||||
{
|
// {
|
||||||
var gracePeriodConfirmedEvent = new GracePeriodConfirmedIntegrationEvent(orderId);
|
// var gracePeriodConfirmedEvent = new GracePeriodConfirmedIntegrationEvent(orderId);
|
||||||
_eventBus.Publish(gracePeriodConfirmedEvent);
|
// _eventBus.Publish(gracePeriodConfirmedEvent);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
private IEnumerable<int> GetConfirmedGracePeriodOrders()
|
// private IEnumerable<int> GetConfirmedGracePeriodOrders()
|
||||||
{
|
// {
|
||||||
IEnumerable<int> orderIds = new List<int>();
|
// IEnumerable<int> orderIds = new List<int>();
|
||||||
|
|
||||||
using (var conn = new SqlConnection(_settings.ConnectionString))
|
// using (var conn = new SqlConnection(_settings.ConnectionString))
|
||||||
{
|
// {
|
||||||
try
|
// try
|
||||||
{
|
// {
|
||||||
conn.Open();
|
// conn.Open();
|
||||||
orderIds = conn.Query<int>(
|
// orderIds = conn.Query<int>(
|
||||||
@"SELECT Id FROM [ordering].[orders]
|
// @"SELECT Id FROM [ordering].[orders]
|
||||||
WHERE DATEDIFF(minute, [OrderDate], GETDATE()) >= @GracePeriodTime
|
// WHERE DATEDIFF(minute, [OrderDate], GETDATE()) >= @GracePeriodTime
|
||||||
AND [OrderStatusId] = 1",
|
// AND [OrderStatusId] = 1",
|
||||||
new { GracePeriodTime = _settings.GracePeriodTime });
|
// new { GracePeriodTime = _settings.GracePeriodTime });
|
||||||
}
|
// }
|
||||||
catch (SqlException exception)
|
// catch (SqlException exception)
|
||||||
{
|
// {
|
||||||
_logger.LogCritical($"FATAL ERROR: Database connections could not be opened: {exception.Message}");
|
// _logger.LogCritical($"FATAL ERROR: Database connections could not be opened: {exception.Message}");
|
||||||
}
|
// }
|
||||||
|
|
||||||
}
|
// }
|
||||||
|
|
||||||
return orderIds;
|
// return orderIds;
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
}
|
}
|
||||||
|
@ -58,8 +58,8 @@
|
|||||||
}).AddControllersAsServices(); //Injecting Controllers themselves thru DI
|
}).AddControllersAsServices(); //Injecting Controllers themselves thru DI
|
||||||
//For further info see: http://docs.autofac.org/en/latest/integration/aspnetcore.html#controllers-as-services
|
//For further info see: http://docs.autofac.org/en/latest/integration/aspnetcore.html#controllers-as-services
|
||||||
|
|
||||||
// Configure GracePeriodManager Hosted Service
|
//// Configure GracePeriodManager Hosted Service
|
||||||
services.AddSingleton<IHostedService, GracePeriodManagerService>();
|
//services.AddSingleton<IHostedService, GracePeriodManagerService>();
|
||||||
|
|
||||||
services.AddTransient<IOrderingIntegrationEventService, OrderingIntegrationEventService>();
|
services.AddTransient<IOrderingIntegrationEventService, OrderingIntegrationEventService>();
|
||||||
|
|
||||||
|
@ -0,0 +1,13 @@
|
|||||||
|
namespace Ordering.BackgroundTasks.Configuration
|
||||||
|
{
|
||||||
|
public class BackgroundTaskSettings
|
||||||
|
{
|
||||||
|
public string ConnectionString { get; set; }
|
||||||
|
|
||||||
|
public string EventBusConnection { get; set; }
|
||||||
|
|
||||||
|
public int GracePeriodTime { get; set; }
|
||||||
|
|
||||||
|
public int CheckUpdateTime { get; set; }
|
||||||
|
}
|
||||||
|
}
|
18
src/Services/Ordering/Ordering.BackgroundTasks/Dockerfile
Normal file
18
src/Services/Ordering/Ordering.BackgroundTasks/Dockerfile
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
FROM microsoft/aspnetcore:2.0.3 AS base
|
||||||
|
WORKDIR /app
|
||||||
|
EXPOSE 80
|
||||||
|
|
||||||
|
FROM microsoft/aspnetcore-build:2.0 AS build
|
||||||
|
WORKDIR /src
|
||||||
|
COPY . .
|
||||||
|
RUN dotnet restore -nowarn:msb3202,nu1503
|
||||||
|
WORKDIR /src/src/Services/Ordering/Ordering.BackgroundTasks
|
||||||
|
RUN dotnet build --no-restore -c Release -o /app
|
||||||
|
|
||||||
|
FROM build AS publish
|
||||||
|
RUN dotnet publish --no-restore -c Release -o /app
|
||||||
|
|
||||||
|
FROM base AS final
|
||||||
|
WORKDIR /app
|
||||||
|
COPY --from=publish /app .
|
||||||
|
ENTRYPOINT ["dotnet", "Ordering.BackgroundTasks.dll"]
|
@ -0,0 +1,12 @@
|
|||||||
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
|
||||||
|
|
||||||
|
namespace Ordering.BackgroundTasks.IntegrationEvents
|
||||||
|
{
|
||||||
|
public class GracePeriodConfirmedIntegrationEvent : IntegrationEvent
|
||||||
|
{
|
||||||
|
public int OrderId { get; }
|
||||||
|
|
||||||
|
public GracePeriodConfirmedIntegrationEvent(int orderId) =>
|
||||||
|
OrderId = orderId;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||||
|
<DockerComposeProjectPath>..\..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Folder Include="wwwroot\" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.2.0" />
|
||||||
|
<PackageReference Include="Dapper" Version="1.50.4" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.5" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="2.0.2" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBusRabbitMQ\EventBusRabbitMQ.csproj" />
|
||||||
|
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBusServiceBus\EventBusServiceBus.csproj" />
|
||||||
|
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBus\EventBus.csproj" />
|
||||||
|
<ProjectReference Include="..\..\..\BuildingBlocks\HealthChecks\src\Microsoft.AspNetCore.HealthChecks\Microsoft.AspNetCore.HealthChecks.csproj" />
|
||||||
|
<ProjectReference Include="..\..\..\BuildingBlocks\HealthChecks\src\Microsoft.Extensions.HealthChecks.SqlServer\Microsoft.Extensions.HealthChecks.SqlServer.csproj" />
|
||||||
|
<ProjectReference Include="..\..\..\BuildingBlocks\HealthChecks\src\Microsoft.Extensions.HealthChecks\Microsoft.Extensions.HealthChecks.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
24
src/Services/Ordering/Ordering.BackgroundTasks/Program.cs
Normal file
24
src/Services/Ordering/Ordering.BackgroundTasks/Program.cs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
using Microsoft.AspNetCore;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
|
namespace Ordering.BackgroundTasks
|
||||||
|
{
|
||||||
|
public class Program
|
||||||
|
{
|
||||||
|
public static void Main(string[] args)
|
||||||
|
{
|
||||||
|
BuildWebHost(args).Run();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IWebHost BuildWebHost(string[] args) =>
|
||||||
|
WebHost.CreateDefaultBuilder(args)
|
||||||
|
.UseStartup<Startup>()
|
||||||
|
.ConfigureLogging((hostingContext, builder) =>
|
||||||
|
{
|
||||||
|
builder.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
|
||||||
|
builder.AddDebug();
|
||||||
|
builder.AddConsole();
|
||||||
|
}).Build();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"iisSettings": {
|
||||||
|
"windowsAuthentication": false,
|
||||||
|
"anonymousAuthentication": true,
|
||||||
|
"iisExpress": {
|
||||||
|
"applicationUrl": "http://localhost:5161/",
|
||||||
|
"sslPort": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"profiles": {
|
||||||
|
"IIS Express": {
|
||||||
|
"commandName": "IISExpress",
|
||||||
|
"launchBrowser": true,
|
||||||
|
"launchUrl": "api/values",
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Ordering.BackgroundTasks": {
|
||||||
|
"commandName": "Project",
|
||||||
|
"launchBrowser": true,
|
||||||
|
"launchUrl": "api/values",
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
},
|
||||||
|
"applicationUrl": "http://localhost:5162/"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
158
src/Services/Ordering/Ordering.BackgroundTasks/Startup.cs
Normal file
158
src/Services/Ordering/Ordering.BackgroundTasks/Startup.cs
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
using Autofac;
|
||||||
|
using Autofac.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.Azure.ServiceBus;
|
||||||
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus;
|
||||||
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
|
||||||
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ;
|
||||||
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBusServiceBus;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.HealthChecks;
|
||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Ordering.BackgroundTasks.Configuration;
|
||||||
|
using Ordering.BackgroundTasks.Tasks;
|
||||||
|
using RabbitMQ.Client;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Ordering.BackgroundTasks
|
||||||
|
{
|
||||||
|
public class Startup
|
||||||
|
{
|
||||||
|
public Startup(IConfiguration configuration)
|
||||||
|
{
|
||||||
|
Configuration = configuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IConfiguration Configuration { get; }
|
||||||
|
|
||||||
|
// This method gets called by the runtime. Use this method to add services to the container.
|
||||||
|
public IServiceProvider ConfigureServices(IServiceCollection services)
|
||||||
|
{
|
||||||
|
//add health check for this service
|
||||||
|
services.AddHealthChecks(checks =>
|
||||||
|
{
|
||||||
|
var minutes = 1;
|
||||||
|
|
||||||
|
if (int.TryParse(Configuration["HealthCheck:Timeout"], out var minutesParsed))
|
||||||
|
{
|
||||||
|
minutes = minutesParsed;
|
||||||
|
}
|
||||||
|
checks.AddSqlCheck("OrderingDb", Configuration["ConnectionString"], TimeSpan.FromMinutes(minutes));
|
||||||
|
});
|
||||||
|
|
||||||
|
//configure settings
|
||||||
|
|
||||||
|
services.Configure<BackgroundTaskSettings>(Configuration);
|
||||||
|
services.AddOptions();
|
||||||
|
|
||||||
|
//configure background task
|
||||||
|
|
||||||
|
services.AddSingleton<IHostedService, GracePeriodManagerService>();
|
||||||
|
|
||||||
|
//configure event bus related services
|
||||||
|
|
||||||
|
if (Configuration.GetValue<bool>("AzureServiceBusEnabled"))
|
||||||
|
{
|
||||||
|
services.AddSingleton<IServiceBusPersisterConnection>(sp =>
|
||||||
|
{
|
||||||
|
var logger = sp.GetRequiredService<ILogger<DefaultServiceBusPersisterConnection>>();
|
||||||
|
|
||||||
|
var serviceBusConnectionString = Configuration["EventBusConnection"];
|
||||||
|
var serviceBusConnection = new ServiceBusConnectionStringBuilder(serviceBusConnectionString);
|
||||||
|
|
||||||
|
return new DefaultServiceBusPersisterConnection(serviceBusConnection, logger);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
services.AddSingleton<IRabbitMQPersistentConnection>(sp =>
|
||||||
|
{
|
||||||
|
var logger = sp.GetRequiredService<ILogger<DefaultRabbitMQPersistentConnection>>();
|
||||||
|
|
||||||
|
|
||||||
|
var factory = new ConnectionFactory()
|
||||||
|
{
|
||||||
|
HostName = Configuration["EventBusConnection"]
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(Configuration["EventBusUserName"]))
|
||||||
|
{
|
||||||
|
factory.UserName = Configuration["EventBusUserName"];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(Configuration["EventBusPassword"]))
|
||||||
|
{
|
||||||
|
factory.Password = Configuration["EventBusPassword"];
|
||||||
|
}
|
||||||
|
|
||||||
|
var retryCount = 5;
|
||||||
|
if (!string.IsNullOrEmpty(Configuration["EventBusRetryCount"]))
|
||||||
|
{
|
||||||
|
retryCount = int.Parse(Configuration["EventBusRetryCount"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new DefaultRabbitMQPersistentConnection(factory, logger, retryCount);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
RegisterEventBus(services);
|
||||||
|
|
||||||
|
//create autofac based service provider
|
||||||
|
var container = new ContainerBuilder();
|
||||||
|
container.Populate(services);
|
||||||
|
|
||||||
|
|
||||||
|
return new AutofacServiceProvider(container.Build());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||||
|
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void RegisterEventBus(IServiceCollection services)
|
||||||
|
{
|
||||||
|
var subscriptionClientName = Configuration["SubscriptionClientName"];
|
||||||
|
|
||||||
|
if (Configuration.GetValue<bool>("AzureServiceBusEnabled"))
|
||||||
|
{
|
||||||
|
services.AddSingleton<IEventBus, EventBusServiceBus>(sp =>
|
||||||
|
{
|
||||||
|
var serviceBusPersisterConnection = sp.GetRequiredService<IServiceBusPersisterConnection>();
|
||||||
|
var iLifetimeScope = sp.GetRequiredService<ILifetimeScope>();
|
||||||
|
var logger = sp.GetRequiredService<ILogger<EventBusServiceBus>>();
|
||||||
|
var eventBusSubcriptionsManager = sp.GetRequiredService<IEventBusSubscriptionsManager>();
|
||||||
|
|
||||||
|
return new EventBusServiceBus(serviceBusPersisterConnection, logger,
|
||||||
|
eventBusSubcriptionsManager, subscriptionClientName, iLifetimeScope);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
services.AddSingleton<IEventBus, EventBusRabbitMQ>(sp =>
|
||||||
|
{
|
||||||
|
var rabbitMQPersistentConnection = sp.GetRequiredService<IRabbitMQPersistentConnection>();
|
||||||
|
var iLifetimeScope = sp.GetRequiredService<ILifetimeScope>();
|
||||||
|
var logger = sp.GetRequiredService<ILogger<EventBusRabbitMQ>>();
|
||||||
|
var eventBusSubcriptionsManager = sp.GetRequiredService<IEventBusSubscriptionsManager>();
|
||||||
|
|
||||||
|
var retryCount = 5;
|
||||||
|
if (!string.IsNullOrEmpty(Configuration["EventBusRetryCount"]))
|
||||||
|
{
|
||||||
|
retryCount = int.Parse(Configuration["EventBusRetryCount"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new EventBusRabbitMQ(rabbitMQPersistentConnection, logger, iLifetimeScope, eventBusSubcriptionsManager, subscriptionClientName, retryCount);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
services.AddSingleton<IEventBusSubscriptionsManager, InMemoryEventBusSubscriptionsManager>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,81 @@
|
|||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Ordering.BackgroundTasks.Tasks.Base
|
||||||
|
{
|
||||||
|
// Copyright(c) .NET Foundation.All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Base class for implementing a long running <see cref="IHostedService"/>.
|
||||||
|
/// IMPORTANT: This base class is implemented in .NET Core 2.1 - Since this microservice is still in .NET Core 2.0, we're using the class within the project
|
||||||
|
/// When .NET Core 2.1 is released, this class should be removed and you should use the use implemented by the framework
|
||||||
|
/// https://github.com/aspnet/Hosting/blob/712c992ca827576c05923e6a134ca0bec87af4df/src/Microsoft.Extensions.Hosting.Abstractions/BackgroundService.cs
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public abstract class BackgroundService : IHostedService, IDisposable
|
||||||
|
{
|
||||||
|
private Task _executingTask;
|
||||||
|
|
||||||
|
private readonly CancellationTokenSource _stoppingCts = new CancellationTokenSource();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This method is called when the <see cref="IHostedService"/> starts. The implementation should return a task that represents
|
||||||
|
/// the lifetime of the long running operation(s) being performed.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stoppingToken">Triggered when <see cref="IHostedService.StopAsync(CancellationToken)"/> is called.</param>
|
||||||
|
/// <returns>A <see cref="Task"/> that represents the long running operations.</returns>
|
||||||
|
protected abstract Task ExecuteAsync(CancellationToken stoppingToken);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Triggered when the application host is ready to start the service.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="cancellationToken">Indicates that the start process has been aborted.</param>
|
||||||
|
public virtual Task StartAsync(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
// Store the task we're executing
|
||||||
|
_executingTask = ExecuteAsync(_stoppingCts.Token);
|
||||||
|
|
||||||
|
// If the task is completed then return it, this will bubble cancellation and failure to the caller
|
||||||
|
if (_executingTask.IsCompleted)
|
||||||
|
{
|
||||||
|
return _executingTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise it's running
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Triggered when the application host is performing a graceful shutdown.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="cancellationToken">Indicates that the shutdown process should no longer be graceful.</param>
|
||||||
|
public virtual async Task StopAsync(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
// Stop called without start
|
||||||
|
if (_executingTask == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Signal cancellation to the executing method
|
||||||
|
_stoppingCts.Cancel();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
// Wait until the task completes or the stop token triggers
|
||||||
|
await Task.WhenAny(_executingTask, Task.Delay(Timeout.Infinite, cancellationToken));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void Dispose()
|
||||||
|
{
|
||||||
|
_stoppingCts.Cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,92 @@
|
|||||||
|
using Dapper;
|
||||||
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using Ordering.BackgroundTasks.Configuration;
|
||||||
|
using Ordering.BackgroundTasks.IntegrationEvents;
|
||||||
|
using Ordering.BackgroundTasks.Tasks.Base;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data.SqlClient;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Ordering.BackgroundTasks.Tasks
|
||||||
|
{
|
||||||
|
public class GracePeriodManagerService
|
||||||
|
: BackgroundService
|
||||||
|
{
|
||||||
|
private readonly ILogger<GracePeriodManagerService> _logger;
|
||||||
|
private readonly BackgroundTaskSettings _settings;
|
||||||
|
private readonly IEventBus _eventBus;
|
||||||
|
|
||||||
|
public GracePeriodManagerService(IOptions<BackgroundTaskSettings> settings,
|
||||||
|
IEventBus eventBus,
|
||||||
|
ILogger<GracePeriodManagerService> logger)
|
||||||
|
{
|
||||||
|
_settings = settings?.Value ?? throw new ArgumentNullException(nameof(settings));
|
||||||
|
_eventBus = eventBus ?? throw new ArgumentNullException(nameof(eventBus));
|
||||||
|
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||||
|
{
|
||||||
|
_logger.LogDebug($"GracePeriodManagerService is starting.");
|
||||||
|
|
||||||
|
stoppingToken.Register(() => _logger.LogDebug($"#1 GracePeriodManagerService background task is stopping."));
|
||||||
|
|
||||||
|
while (!stoppingToken.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
_logger.LogDebug($"GracePeriodManagerService background task is doing background work.");
|
||||||
|
|
||||||
|
CheckConfirmedGracePeriodOrders();
|
||||||
|
|
||||||
|
await Task.Delay(_settings.CheckUpdateTime, stoppingToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.LogDebug($"GracePeriodManagerService background task is stopping.");
|
||||||
|
|
||||||
|
await Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CheckConfirmedGracePeriodOrders()
|
||||||
|
{
|
||||||
|
_logger.LogDebug($"Checking confirmed grace period orders");
|
||||||
|
|
||||||
|
var orderIds = GetConfirmedGracePeriodOrders();
|
||||||
|
|
||||||
|
foreach (var orderId in orderIds)
|
||||||
|
{
|
||||||
|
var confirmGracePeriodEvent = new GracePeriodConfirmedIntegrationEvent(orderId);
|
||||||
|
|
||||||
|
_eventBus.Publish(confirmGracePeriodEvent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable<int> GetConfirmedGracePeriodOrders()
|
||||||
|
{
|
||||||
|
IEnumerable<int> orderIds = new List<int>();
|
||||||
|
|
||||||
|
using (var conn = new SqlConnection(_settings.ConnectionString))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
conn.Open();
|
||||||
|
orderIds = conn.Query<int>(
|
||||||
|
@"SELECT Id FROM [ordering].[orders]
|
||||||
|
WHERE DATEDIFF(minute, [OrderDate], GETDATE()) >= @GracePeriodTime
|
||||||
|
AND [OrderStatusId] = 1",
|
||||||
|
new { GracePeriodTime = _settings.GracePeriodTime });
|
||||||
|
}
|
||||||
|
catch (SqlException exception)
|
||||||
|
{
|
||||||
|
_logger.LogCritical($"FATAL ERROR: Database connections could not be opened: {exception.Message}");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return orderIds;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"Logging": {
|
||||||
|
"IncludeScopes": false,
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Debug",
|
||||||
|
"System": "Information",
|
||||||
|
"Microsoft": "Information"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"ConnectionString": "Server=tcp:127.0.0.1,5433;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word;",
|
||||||
|
"Logging": {
|
||||||
|
"IncludeScopes": false,
|
||||||
|
"Debug": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Debug"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Console": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Debug"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"SubscriptionClientName": "Ordering",
|
||||||
|
"GracePeriodTime": "1",
|
||||||
|
"CheckUpdateTime": "1000",
|
||||||
|
"ApplicationInsights": {
|
||||||
|
"InstrumentationKey": ""
|
||||||
|
},
|
||||||
|
"AzureServiceBusEnabled": false,
|
||||||
|
"EventBusRetryCount": 5,
|
||||||
|
"EventBusConnection": "",
|
||||||
|
"EventBusUserName": "",
|
||||||
|
"EventBusPassword": ""
|
||||||
|
}
|
@ -95,8 +95,9 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.O
|
|||||||
{
|
{
|
||||||
if (_orderStatusId == OrderStatus.Submitted.Id)
|
if (_orderStatusId == OrderStatus.Submitted.Id)
|
||||||
{
|
{
|
||||||
AddDomainEvent(new OrderStatusChangedToAwaitingValidationDomainEvent(Id, _orderItems));
|
|
||||||
_orderStatusId = OrderStatus.AwaitingValidation.Id;
|
_orderStatusId = OrderStatus.AwaitingValidation.Id;
|
||||||
|
|
||||||
|
AddDomainEvent(new OrderStatusChangedToAwaitingValidationDomainEvent(Id, _orderItems));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,10 +105,10 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.O
|
|||||||
{
|
{
|
||||||
if (_orderStatusId == OrderStatus.AwaitingValidation.Id)
|
if (_orderStatusId == OrderStatus.AwaitingValidation.Id)
|
||||||
{
|
{
|
||||||
AddDomainEvent(new OrderStatusChangedToStockConfirmedDomainEvent(Id));
|
|
||||||
|
|
||||||
_orderStatusId = OrderStatus.StockConfirmed.Id;
|
_orderStatusId = OrderStatus.StockConfirmed.Id;
|
||||||
_description = "All the items were confirmed with available stock.";
|
_description = "All the items were confirmed with available stock.";
|
||||||
|
|
||||||
|
AddDomainEvent(new OrderStatusChangedToStockConfirmedDomainEvent(Id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,10 +116,10 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.O
|
|||||||
{
|
{
|
||||||
if (_orderStatusId == OrderStatus.StockConfirmed.Id)
|
if (_orderStatusId == OrderStatus.StockConfirmed.Id)
|
||||||
{
|
{
|
||||||
AddDomainEvent(new OrderStatusChangedToPaidDomainEvent(Id, OrderItems));
|
|
||||||
|
|
||||||
_orderStatusId = OrderStatus.Paid.Id;
|
_orderStatusId = OrderStatus.Paid.Id;
|
||||||
_description = "The payment was performed at a simulated \"American Bank checking bank account endinf on XX35071\"";
|
_description = "The payment was performed at a simulated \"American Bank checking bank account endinf on XX35071\"";
|
||||||
|
|
||||||
|
AddDomainEvent(new OrderStatusChangedToPaidDomainEvent(Id, OrderItems));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user