From df298bcff8def289a824dafb7c97e4dd13fa1a4e Mon Sep 17 00:00:00 2001 From: Stuart Ferguson Date: Fri, 9 Jun 2023 10:56:41 +0100 Subject: [PATCH] more tweaks added for error handling and logging --- .../BaseJob.cs | 54 ++++++++++++ .../Bootstrapper.cs | 33 +------- .../GenerateFileUploadsJob.cs | 12 +-- .../GenerateMerchantStatementJob.cs | 22 ++--- .../GenerateTransactionsJob.cs | 34 ++++---- .../Jobs.cs | 84 +++++++++++++++---- .../ProcessSettlementJob.cs | 7 +- .../SupportReportEmailJob.cs | 5 ++ ...ionProcessing.SchedulerService.Jobs.csproj | 6 +- .../Startup.cs | 7 +- ...nsactionProcessing.SchedulerService.csproj | 2 +- .../nlog.config | 21 +---- 12 files changed, 173 insertions(+), 114 deletions(-) create mode 100644 TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.Jobs/BaseJob.cs diff --git a/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.Jobs/BaseJob.cs b/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.Jobs/BaseJob.cs new file mode 100644 index 0000000..b9d9a6c --- /dev/null +++ b/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.Jobs/BaseJob.cs @@ -0,0 +1,54 @@ +namespace TransactionProcessing.SchedulerService.Jobs; + +using System; +using System.Threading; +using System.Threading.Tasks; +using DataGeneration; +using EstateManagement.Client; +using SecurityService.Client; +using SecurityService.DataTransferObjects.Responses; +using Shared.Logger; +using TransactionProcessor.Client; + +public abstract class BaseJob{ + public String JobName { get; set; } + + protected ITransactionDataGenerator CreateTransactionDataGenerator(String clientId, String clientSecret, RunningMode runningMode){ + ISecurityServiceClient securityServiceClient = Bootstrapper.GetService(); + IEstateClient estateClient = Bootstrapper.GetService(); + ITransactionProcessorClient transactionProcessorClient = Bootstrapper.GetService(); + Func baseAddressFunc = Bootstrapper.GetService>(); + + ITransactionDataGenerator g = new TransactionDataGenerator(securityServiceClient, + estateClient, + transactionProcessorClient, + baseAddressFunc("EstateManagementApi"), + baseAddressFunc("FileProcessorApi"), + baseAddressFunc("TestHostApi"), + clientId, + clientSecret, + runningMode); + return g; + } + + protected async Task GetToken(String clientId, String clientSecret, CancellationToken cancellationToken) + { + ISecurityServiceClient securityServiceClient = Bootstrapper.GetService(); + TokenResponse token = await securityServiceClient.GetToken(clientId, clientSecret, cancellationToken); + + return token.AccessToken; + } + + protected void TraceGenerated(TraceEventArgs traceArguments) + { + if (traceArguments.TraceLevel == TraceEventArgs.Level.Error){ + Logger.LogError(new Exception(traceArguments.Message)); + } + else if (traceArguments.TraceLevel == TraceEventArgs.Level.Warning){ + Logger.LogWarning(traceArguments.Message); + } + else{ + Logger.LogInformation(traceArguments.Message); + } + } +} \ No newline at end of file diff --git a/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.Jobs/Bootstrapper.cs b/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.Jobs/Bootstrapper.cs index d985864..4d601ac 100644 --- a/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.Jobs/Bootstrapper.cs +++ b/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.Jobs/Bootstrapper.cs @@ -1,17 +1,14 @@ namespace TransactionProcessing.SchedulerService.Jobs; using System; +using System.Diagnostics.Eventing.Reader; using System.Net.Http; -using System.Threading.Tasks; -using System.Threading; -using DataGeneration; using EstateManagement.Client; using EstateManagement.DataTransferObjects.Responses; using MessagingService.Client; using Microsoft.Extensions.DependencyInjection; using Quartz; using SecurityService.Client; -using SecurityService.DataTransferObjects.Responses; using TransactionProcessor.Client; public static class Bootstrapper{ @@ -50,32 +47,4 @@ public static T GetService() { return Bootstrapper.ServiceProvider.GetService(); } -} - -public class BaseJob{ - protected ITransactionDataGenerator CreateTransactionDataGenerator(String clientId, String clientSecret, RunningMode runningMode){ - ISecurityServiceClient securityServiceClient = Bootstrapper.GetService(); - IEstateClient estateClient = Bootstrapper.GetService(); - TransactionProcessorClient transactionProcessorClient = Bootstrapper.GetService(); - Func baseAddressFunc = Bootstrapper.GetService>(); - - ITransactionDataGenerator g = new TransactionDataGenerator(securityServiceClient, - estateClient, - transactionProcessorClient, - baseAddressFunc("EstateManagementApi"), - baseAddressFunc("FileProcessorApi"), - baseAddressFunc("TestHostApi"), - clientId, - clientSecret, - runningMode); - return g; - } - - protected async Task GetToken(String clientId, String clientSecret, CancellationToken cancellationToken) - { - ISecurityServiceClient securityServiceClient = Bootstrapper.GetService(); - TokenResponse token = await securityServiceClient.GetToken(clientId, clientSecret, cancellationToken); - - return token.AccessToken; - } } \ No newline at end of file diff --git a/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.Jobs/GenerateFileUploadsJob.cs b/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.Jobs/GenerateFileUploadsJob.cs index a91e432..982661a 100644 --- a/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.Jobs/GenerateFileUploadsJob.cs +++ b/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.Jobs/GenerateFileUploadsJob.cs @@ -6,7 +6,7 @@ using DataGeneration; using EstateManagement.DataTransferObjects.Responses; using Quartz; - using Quartz.Logging; + using Shared.Logger; [DisallowConcurrentExecution] public class GenerateFileUploadsJob : BaseJob, IJob @@ -21,13 +21,15 @@ public async Task Execute(IJobExecutionContext context) Guid estateId = context.MergedJobDataMap.GetGuidValueFromString("EstateId"); Guid merchantId = context.MergedJobDataMap.GetGuidValueFromString("MerchantId"); - ITransactionDataGenerator t = CreateTransactionDataGenerator(clientId, clientSecret, RunningMode.Live); + Logger.LogInformation($"Running Job {context.JobDetail.Description}"); + Logger.LogInformation($"Client Id: [{clientId}]"); + Logger.LogInformation($"Estate Id: [{estateId}]"); + Logger.LogInformation($"Merchant Id: [{merchantId}]"); + ITransactionDataGenerator t = CreateTransactionDataGenerator(clientId, clientSecret, RunningMode.Live); + t.TraceGenerated += TraceGenerated; await Jobs.GenerateFileUploads(t, estateId, merchantId, context.CancellationToken); } - - - #endregion } } \ No newline at end of file diff --git a/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.Jobs/GenerateMerchantStatementJob.cs b/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.Jobs/GenerateMerchantStatementJob.cs index 1af3a81..8c705de 100644 --- a/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.Jobs/GenerateMerchantStatementJob.cs +++ b/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.Jobs/GenerateMerchantStatementJob.cs @@ -4,6 +4,7 @@ using System.Threading.Tasks; using DataGeneration; using Quartz; +using Shared.Logger; public class GenerateMerchantStatementJob : BaseJob, IJob { @@ -14,23 +15,12 @@ public async Task Execute(IJobExecutionContext context) String clientSecret = context.MergedJobDataMap.GetString("ClientSecret"); Guid estateId = context.MergedJobDataMap.GetGuidValueFromString("EstateId"); + Logger.LogInformation($"Running Job {context.JobDetail.Description}"); + Logger.LogInformation($"Client Id: [{clientId}]"); + Logger.LogInformation($"Estate Id: [{estateId}]"); + ITransactionDataGenerator t = this.CreateTransactionDataGenerator(clientId, clientSecret, RunningMode.Live); - + t.TraceGenerated += TraceGenerated; await Jobs.GenerateMerchantStatements(t, estateId, context.CancellationToken); } -} - -public class SupportReportJob : BaseJob, IJob -{ - public async Task Execute(IJobExecutionContext context) - { - Bootstrapper.ConfigureServices(context); - - String eventStoreAddress = context.MergedJobDataMap.GetString("EventStoreAddress"); - String databaseConnectionString = context.MergedJobDataMap.GetString("DatabaseConnectionString"); - - // Events in Parked Queues - // Incomplete Files - } - } \ No newline at end of file diff --git a/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.Jobs/GenerateTransactionsJob.cs b/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.Jobs/GenerateTransactionsJob.cs index 11634ef..3492daf 100644 --- a/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.Jobs/GenerateTransactionsJob.cs +++ b/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.Jobs/GenerateTransactionsJob.cs @@ -28,25 +28,25 @@ public class GenerateTransactionsJob : BaseJob, IJob{ #region Methods public async Task Execute(IJobExecutionContext context){ - Bootstrapper.ConfigureServices(context); + this.JobName = context.JobDetail.Description; + Bootstrapper.ConfigureServices(context); - String clientId = context.MergedJobDataMap.GetString("ClientId"); - String clientSecret = context.MergedJobDataMap.GetString("ClientSecret"); - Guid estateId = context.MergedJobDataMap.GetGuidValueFromString("EstateId"); - Guid merchantId = context.MergedJobDataMap.GetGuidValueFromString("MerchantId"); - Boolean requireLogon = context.MergedJobDataMap.GetBooleanValueFromString("requireLogon"); + String clientId = context.MergedJobDataMap.GetString("ClientId"); + String clientSecret = context.MergedJobDataMap.GetString("ClientSecret"); + Guid estateId = context.MergedJobDataMap.GetGuidValueFromString("EstateId"); + Guid merchantId = context.MergedJobDataMap.GetGuidValueFromString("MerchantId"); + Boolean requireLogon = context.MergedJobDataMap.GetBooleanValueFromString("requireLogon"); + + Logger.LogInformation($"Running Job {context.JobDetail.Description}"); + Logger.LogInformation($"Client Id: [{clientId}]"); + Logger.LogInformation($"Estate Id: [{estateId}]"); + Logger.LogInformation($"Merchant Id: [{merchantId}]"); + Logger.LogInformation($"Require Logon: [{requireLogon}]"); - Logger.LogInformation($"Running Job {context.JobDetail.Description}"); - Logger.LogInformation($"Client Id: [{clientId}]"); - Logger.LogInformation($"Client Secret: [{clientSecret}]"); - Logger.LogInformation($"Estate Id: [{estateId}]"); - Logger.LogInformation($"Merchant Id: [{merchantId}]"); - Logger.LogInformation($"Require Logon: [{requireLogon}]"); - - ITransactionDataGenerator t = CreateTransactionDataGenerator(clientId, clientSecret, RunningMode.Live); - - await Jobs.GenerateTransactions(t, estateId, merchantId, requireLogon, context.CancellationToken); - } + ITransactionDataGenerator t = CreateTransactionDataGenerator(clientId, clientSecret, RunningMode.Live); + t.TraceGenerated += TraceGenerated; + await Jobs.GenerateTransactions(t, estateId, merchantId, requireLogon, context.CancellationToken); + } #endregion } } \ No newline at end of file diff --git a/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.Jobs/Jobs.cs b/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.Jobs/Jobs.cs index 3ff3ce4..fb3ba62 100644 --- a/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.Jobs/Jobs.cs +++ b/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.Jobs/Jobs.cs @@ -14,6 +14,7 @@ using MessagingService.Client; using MessagingService.DataTransferObjects; using Microsoft.Data.SqlClient; +using Microsoft.VisualBasic; using Newtonsoft.Json; using Quartz; using Shared.Logger; @@ -21,9 +22,22 @@ public static class Jobs{ public static async Task GenerateMerchantStatements(ITransactionDataGenerator t, Guid estateId, CancellationToken cancellationToken){ List merchants = await t.GetMerchants(estateId, cancellationToken); + + if (merchants.Any() == false){ + throw new JobExecutionException($"No merchants returned for Estate [{estateId}]"); + } + + List results = new List(); foreach (MerchantResponse merchantResponse in merchants) { - await t.GenerateMerchantStatement(merchantResponse.EstateId, merchantResponse.MerchantId, DateTime.Now, cancellationToken); + Boolean success = await t.GenerateMerchantStatement(merchantResponse.EstateId, merchantResponse.MerchantId, DateTime.Now, cancellationToken); + if (success == false){ + results.Add(merchantResponse.MerchantName); + } + } + + if (results.Any()){ + throw new JobExecutionException($"Error generating statements for merchants [{String.Join(",", results)}]"); } } @@ -31,51 +45,85 @@ public static async Task GenerateFileUploads(ITransactionDataGenerator t, Guid e { MerchantResponse merchant = await t.GetMerchant(estateId, merchantId, cancellationToken); + if (merchant == default) + { + throw new JobExecutionException($"No merchant returned for Estate Id [{estateId}] Merchant Id [{merchantId}]"); + } + List contracts = await t.GetMerchantContracts(merchant, cancellationToken); DateTime fileDate = DateTime.Now; + List results = new List(); foreach (ContractResponse contract in contracts) { // Generate a file and upload - await t.SendUploadFile(fileDate, contract, merchant, cancellationToken); + Boolean success = await t.SendUploadFile(fileDate, contract, merchant, cancellationToken); + + if (success == false) + { + results.Add(contract.OperatorName); + } + } + + if (results.Any()) + { + throw new JobExecutionException($"Error uploading files for merchant [{merchant.MerchantName}] [{String.Join(",", results)}]"); } } public static async Task GenerateTransactions(ITransactionDataGenerator t, Guid estateId, Guid merchantId, Boolean requireLogon, CancellationToken cancellationToken){ - MerchantResponse merchant = null; // get the merchant - try - { - merchant = await t.GetMerchant(estateId, merchantId, cancellationToken); - } - catch(Exception e){ - Logger.LogWarning($"Error getting merchant record [{merchantId}]"); - throw new JobExecutionException(new Exception($"Error getting merchant record [{merchantId}]"), false); + MerchantResponse merchant = await t.GetMerchant(estateId, merchantId, cancellationToken); + + if (merchant == default){ + throw new JobExecutionException($"Error getting Merchant Id [{merchantId}] for Estate Id [{estateId}]"); } DateTime transactionDate = DateTime.Now; + // Get the merchants contracts + List contracts = await t.GetMerchantContracts(merchant, cancellationToken); + + if (contracts.Any() == false) + { + throw new JobExecutionException($"No contracts returned for Merchant [{merchant.MerchantName}]"); + } + if (requireLogon) { // Do a logon transaction for the merchant - await t.PerformMerchantLogon(transactionDate, merchant, cancellationToken); - } + Boolean logonSuccess = await t.PerformMerchantLogon(transactionDate, merchant, cancellationToken); - // Get the merchants contracts - List contracts = await t.GetMerchantContracts(merchant, cancellationToken); + if (logonSuccess == false) + { + throw new JobExecutionException($"Error performing logon for Merchant [{merchant.MerchantName}]"); + } + } + List results = new List(); foreach (ContractResponse contract in contracts) { // Generate and send some sales - await t.SendSales(transactionDate, merchant, contract, cancellationToken); + Boolean success = await t.SendSales(transactionDate, merchant, contract, cancellationToken); - // Generate a file and upload - await t.SendUploadFile(transactionDate, contract, merchant, cancellationToken); + if (success == false) + { + results.Add(contract.OperatorName); + } + } + + if (results.Any()) + { + throw new JobExecutionException($"Error sending sales files for merchant [{merchant.MerchantName}] [{String.Join(",", results)}]"); } } public static async Task PerformSettlement(ITransactionDataGenerator t, DateTime dateTime, Guid estateId, CancellationToken cancellationToken) { - await t.PerformSettlement(dateTime, estateId, cancellationToken); + Boolean success = await t.PerformSettlement(dateTime, estateId, cancellationToken); + + if (success == false){ + throw new JobExecutionException($"Error performing settlement for Estate Id [{estateId}] and date [{dateTime:dd-MM-yyyy}]"); + } } public static async Task> GetParkedQueueInformation(String eventStoreConnectionString, CancellationToken cancellationToken){ diff --git a/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.Jobs/ProcessSettlementJob.cs b/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.Jobs/ProcessSettlementJob.cs index 3b60f98..e097a0b 100644 --- a/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.Jobs/ProcessSettlementJob.cs +++ b/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.Jobs/ProcessSettlementJob.cs @@ -10,6 +10,7 @@ namespace TransactionProcessing.SchedulerService.Jobs using Quartz; using SecurityService.Client; using SecurityService.DataTransferObjects.Responses; + using Shared.Logger; using TransactionProcessing.DataGeneration; using TransactionProcessor.Client; @@ -22,8 +23,12 @@ public async Task Execute(IJobExecutionContext context) String clientSecret = context.MergedJobDataMap.GetString("ClientSecret"); Guid estateId = context.MergedJobDataMap.GetGuidValueFromString("EstateId"); - ITransactionDataGenerator t = CreateTransactionDataGenerator(clientId, clientSecret, RunningMode.Live); + Logger.LogInformation($"Running Job {context.JobDetail.Description}"); + Logger.LogInformation($"Client Id: [{clientId}]"); + Logger.LogInformation($"Estate Id: [{estateId}]"); + ITransactionDataGenerator t = CreateTransactionDataGenerator(clientId, clientSecret, RunningMode.Live); + t.TraceGenerated += TraceGenerated; await Jobs.PerformSettlement(t, DateTime.Now, estateId, context.CancellationToken); } } diff --git a/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.Jobs/SupportReportEmailJob.cs b/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.Jobs/SupportReportEmailJob.cs index 48acbe7..a49f8ff 100644 --- a/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.Jobs/SupportReportEmailJob.cs +++ b/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.Jobs/SupportReportEmailJob.cs @@ -5,6 +5,7 @@ using System.Threading.Tasks; using MessagingService.Client; using Quartz; +using Shared.Logger; public class SupportReportEmailJob : BaseJob, IJob { @@ -19,6 +20,10 @@ public async Task Execute(IJobExecutionContext context) String databaseConnectionString = context.MergedJobDataMap.GetString("DatabaseConnectionString"); String estateIds = context.MergedJobDataMap.GetString("EstateIds"); + Logger.LogInformation($"Running Job {context.JobDetail.Description}"); + Logger.LogInformation($"Client Id: [{clientId}]"); + Logger.LogInformation($"Estate Id: [{estateIds}]"); + String token = await this.GetToken(clientId, clientSecret, context.CancellationToken); IMessagingServiceClient messagingServiceClient = Bootstrapper.GetService(); diff --git a/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.Jobs/TransactionProcessing.SchedulerService.Jobs.csproj b/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.Jobs/TransactionProcessing.SchedulerService.Jobs.csproj index 7e3b52c..d42748a 100644 --- a/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.Jobs/TransactionProcessing.SchedulerService.Jobs.csproj +++ b/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.Jobs/TransactionProcessing.SchedulerService.Jobs.csproj @@ -8,14 +8,14 @@ - + - + - + diff --git a/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService/Startup.cs b/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService/Startup.cs index aadcb25..cc7f8a5 100644 --- a/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService/Startup.cs +++ b/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService/Startup.cs @@ -128,8 +128,11 @@ public void ConfigureServices(IServiceCollection services){ private void RegisterJobs(IServiceCollection services) { - Type type = typeof(IJob); - IEnumerable jobs = AppDomain.CurrentDomain.GetAssemblies().SelectMany(s => s.GetTypes()).Where(p => type.IsAssignableFrom(p) && p.IsInterface == false); + Type type = typeof(BaseJob); + IEnumerable jobs = AppDomain.CurrentDomain.GetAssemblies().SelectMany(s => s.GetTypes()) + .Where(p => type.IsAssignableFrom(p) + && p.IsInterface == false + && p.IsAbstract == false); foreach (Type job in jobs) { diff --git a/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.csproj b/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.csproj index 6db75b4..773cbcd 100644 --- a/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.csproj +++ b/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.csproj @@ -10,7 +10,7 @@ - + diff --git a/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService/nlog.config b/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService/nlog.config index 45e92d0..898db06 100644 --- a/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService/nlog.config +++ b/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService/nlog.config @@ -3,35 +3,18 @@ - - - - - - - - - - - +