@ -1,17 +0,0 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Text; | |||
namespace Ordering.BackgroundTasksHost.Configuration | |||
{ | |||
public class BackgroundTaskSettings | |||
{ | |||
public string ConnectionString { get; set; } | |||
public string EventBusConnection { get; set; } | |||
public int GracePeriodTime { get; set; } | |||
public int CheckUpdateTime { get; set; } | |||
} | |||
} |
@ -1,12 +0,0 @@ | |||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; | |||
namespace Ordering.BackgroundTasksHost.IntegrationEvents | |||
{ | |||
public class GracePeriodConfirmedIntegrationEvent : IntegrationEvent | |||
{ | |||
public int OrderId { get; } | |||
public GracePeriodConfirmedIntegrationEvent(int orderId) => | |||
OrderId = orderId; | |||
} | |||
} |
@ -1,32 +0,0 @@ | |||
<Project Sdk="Microsoft.NET.Sdk"> | |||
<PropertyGroup> | |||
<OutputType>Exe</OutputType> | |||
<TargetFramework>netcoreapp2.1</TargetFramework> | |||
</PropertyGroup> | |||
<ItemGroup> | |||
<None Remove="appsettings.json" /> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<Content Include="appsettings.json"> | |||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory> | |||
</Content> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.2.2" /> | |||
<PackageReference Include="Dapper" Version="1.50.4" /> | |||
<PackageReference Include="Microsoft.AspNetCore.App" Version="2.1.0-rc1-final" /> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBusRabbitMQ\EventBusRabbitMQ.csproj" /> | |||
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBusServiceBus\EventBusServiceBus.csproj" /> | |||
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBus\EventBus.csproj" /> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<Folder Include="Tasks\" /> | |||
</ItemGroup> | |||
</Project> |
@ -1,177 +0,0 @@ | |||
using Autofac.Extensions.DependencyInjection; | |||
using Autofac; | |||
using Microsoft.Extensions.DependencyInjection; | |||
using Microsoft.Extensions.Hosting; | |||
using System; | |||
using Ordering.BackgroundTasksHost.Configuration; | |||
using Microsoft.Extensions.Configuration; | |||
using Microsoft.Extensions.Logging; | |||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBusServiceBus; | |||
using Microsoft.Azure.ServiceBus; | |||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ; | |||
using RabbitMQ.Client; | |||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; | |||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus; | |||
using Ordering.BackgroundTasksHost.Tasks; | |||
namespace Ordering.BackgroundTasksHost | |||
{ | |||
class Program | |||
{ | |||
static void Main(string[] args) | |||
{ | |||
using (var host = CreateHost(args)) | |||
{ | |||
host.Start(); | |||
host.WaitForShutdown(); | |||
} | |||
} | |||
static IHost CreateHost(string[] args) | |||
{ | |||
var host = new HostBuilder() | |||
.ConfigureAppConfiguration((hostContext, configApp) => | |||
{ | |||
configApp.AddEnvironmentVariables(); | |||
configApp.AddJsonFile("appsettings.json", optional: true); | |||
configApp.AddJsonFile( | |||
$"appsettings.{hostContext.HostingEnvironment.EnvironmentName}.json", | |||
optional: true); | |||
configApp.AddCommandLine(args); | |||
}) | |||
.ConfigureServices(services => | |||
{ | |||
var configuration = services.BuildServiceProvider() | |||
.GetRequiredService<IConfiguration>(); | |||
services.AddOptions() | |||
.Configure<BackgroundTaskSettings>(configuration) | |||
.RegisterBus(configuration) | |||
.RegisterHostedServices(); | |||
}) | |||
.UseServiceProviderFactory(new AutofacServiceProviderFactory()) | |||
.Build(); | |||
return host; | |||
} | |||
} | |||
class AutofacServiceProviderFactory | |||
: IServiceProviderFactory<ContainerBuilder> | |||
{ | |||
public ContainerBuilder CreateBuilder(IServiceCollection services) | |||
{ | |||
var containerBuilder = new ContainerBuilder(); | |||
containerBuilder.Populate(services); | |||
return containerBuilder; | |||
} | |||
public IServiceProvider CreateServiceProvider(ContainerBuilder containerBuilder) | |||
{ | |||
return new AutofacServiceProvider(containerBuilder.Build()); | |||
} | |||
} | |||
static class ServiceCollectionExtensions | |||
{ | |||
public static IServiceCollection RegisterBus(this IServiceCollection services, IConfiguration configuration) | |||
{ | |||
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); | |||
}); | |||
} | |||
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>(); | |||
return services; | |||
} | |||
public static IServiceCollection RegisterHostedServices(this IServiceCollection services) | |||
{ | |||
services.AddSingleton<IHostedService, GracePeriodManagerService>(); | |||
return services; | |||
} | |||
} | |||
} |
@ -1,81 +0,0 @@ | |||
using Microsoft.Extensions.Hosting; | |||
using System; | |||
using System.Threading; | |||
using System.Threading.Tasks; | |||
namespace Ordering.BackgroundTasksHost.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(); | |||
} | |||
} | |||
} |
@ -1,92 +0,0 @@ | |||
using Dapper; | |||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; | |||
using Microsoft.Extensions.Hosting; | |||
using Microsoft.Extensions.Logging; | |||
using Microsoft.Extensions.Options; | |||
using Ordering.BackgroundTasksHost.Configuration; | |||
using Ordering.BackgroundTasksHost.IntegrationEvents; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Data.SqlClient; | |||
using System.Threading; | |||
using System.Threading.Tasks; | |||
namespace Ordering.BackgroundTasksHost.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; | |||
} | |||
} | |||
} |
@ -1,27 +0,0 @@ | |||
{ | |||
"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": "BackgroundTasks", | |||
"GracePeriodTime": "1", | |||
"CheckUpdateTime": "1000", | |||
"ApplicationInsights": { | |||
"InstrumentationKey": "" | |||
}, | |||
"AzureServiceBusEnabled": false, | |||
"EventBusRetryCount": 5, | |||
"EventBusConnection": "", | |||
"EventBusUserName": "", | |||
"EventBusPassword": "" | |||
} |