From 1e5fc13a16f5b64dce282206d7cee798070a8374 Mon Sep 17 00:00:00 2001 From: Stuart Ferguson Date: Fri, 2 May 2025 21:52:36 +0100 Subject: [PATCH] Enhance logging and error handling in data generator - Introduced `ConsoleLogger` for improved logging capabilities. - Updated `Program.cs` to utilize new logging and handle async results more robustly. - Refactored `TransactionDataGeneratorService` to return results wrapped in a `Result` type for better error handling. - Modified `Jobs` class to align with new result handling and ensure proper logging of failures. - Updated package references to newer versions for compatibility and potential feature enhancements. - Adjusted date range logic for transaction generation in `Program.cs`. - Replaced direct list manipulations with result checks to enhance code robustness. --- .../DataGenerator/Program.cs | 74 ++++++++++++++++--- .../TransactionDataGeneratorService.cs | 29 +++++++- ...sing.SchedulerService.DataGenerator.csproj | 8 +- .../Jobs/Jobs.cs | 25 ++++--- ...ionProcessing.SchedulerService.Jobs.csproj | 4 +- ...nsactionProcessing.SchedulerService.csproj | 2 +- 6 files changed, 113 insertions(+), 29 deletions(-) diff --git a/TransactionProcessing.SchedulerService/DataGenerator/Program.cs b/TransactionProcessing.SchedulerService/DataGenerator/Program.cs index 31aa99f..40570eb 100644 --- a/TransactionProcessing.SchedulerService/DataGenerator/Program.cs +++ b/TransactionProcessing.SchedulerService/DataGenerator/Program.cs @@ -1,4 +1,5 @@ using System; +using Microsoft.Extensions.Logging; using SimpleResults; using TransactionProcessing.SchedulerService.DataGenerator; using TransactionProcessor.DataTransferObjects.Responses.Contract; @@ -23,8 +24,10 @@ class Program{ private static TransactionProcessorClient TransactionProcessorClient; private static Func baseAddressFunc; - + static async Task Main(string[] args){ + + HttpClientHandler handler = new HttpClientHandler{ ServerCertificateCustomValidationCallback = (message, cert, @@ -58,7 +61,7 @@ static async Task Main(string[] args){ return null; }; - + Shared.Logger.Logger.Initialise(new ConsoleLogger()); Program.SecurityServiceClient = new SecurityServiceClient(baseAddressFunc, httpClient); Program.TransactionProcessorClient = new TransactionProcessorClient(baseAddressFunc, httpClient); @@ -90,7 +93,10 @@ static async Task Main(string[] args){ } private static async Task GenerateStatements(ITransactionDataGeneratorService g, Guid estateId, CancellationToken cancellationToken){ - List merchants = await g.GetMerchants(estateId, cancellationToken); + Result> getMerchantsResult = await g.GetMerchants(estateId, cancellationToken); + if (getMerchantsResult.IsFailed) + return; + List? merchants = getMerchantsResult.Data; foreach (MerchantResponse merchant in merchants){ await g.GenerateMerchantStatement(merchant.EstateId, merchant.MerchantId, DateTime.Now.AddMonths(-2), cancellationToken); } @@ -98,8 +104,8 @@ private static async Task GenerateStatements(ITransactionDataGeneratorService g, private static async Task GenerateTransactions(ITransactionDataGeneratorService g, Guid estateId, CancellationToken cancellationToken){ // Set the date range - DateTime startDate = new DateTime(2025, 4, 14); //27/7 - DateTime endDate = new DateTime(2025, 4,30); // This is the date of the last generated transaction + DateTime startDate = new DateTime(2025, 4, 16); //27/7 + DateTime endDate = new DateTime(2025, 4,16); // This is the date of the last generated transaction Result> dateRangeResult = g.GenerateDateRange(startDate, endDate); if (dateRangeResult.IsFailed) @@ -174,8 +180,12 @@ await g.MakeFloatDeposit(dateTime, estateId, contractResponse.ContractId, { foreach (MerchantResponse merchant in merchantsResult.Data) { // Get the merchants contracts - List contracts = await g.GetMerchantContracts(merchant, cancellationToken); - foreach (ContractResponse contract in contracts) { + Result> getMerchantContractsResult = await g.GetMerchantContracts(merchant, cancellationToken); + if (getMerchantContractsResult.IsFailed) { + Console.WriteLine($"Failed to get merchant contracts: {getMerchantContractsResult.Message}"); + break; + } + foreach (ContractResponse contract in getMerchantContractsResult.Data) { // Generate and send some sales await g.SendSales(dateTime, merchant, contract, 0, cancellationToken); @@ -187,9 +197,13 @@ await g.MakeFloatDeposit(dateTime, estateId, contractResponse.ContractId, if ((dataToSend & DataToSend.Files) == DataToSend.Files) { foreach (MerchantResponse merchant in merchantsResult.Data) { // Get the merchants contracts - List contracts = await g.GetMerchantContracts(merchant, cancellationToken); - - foreach (ContractResponse contract in contracts) { + Result> getMerchantContractsResult = await g.GetMerchantContracts(merchant, cancellationToken); + if (getMerchantContractsResult.IsFailed) + { + Console.WriteLine($"Failed to get merchant contracts: {getMerchantContractsResult.Message}"); + break; + } + foreach (ContractResponse contract in getMerchantContractsResult.Data) { // Generate a file and upload await g.SendUploadFile(dateTime, contract, merchant, Guid.Empty, cancellationToken); @@ -223,4 +237,44 @@ enum DataToSend { Settlement = 16 } } + + public class ConsoleLogger : Shared.Logger.ILogger { + public void LogCritical(Exception exception) { + Console.WriteLine(exception); + } + + public void LogCritical(String message, + Exception exception) { + Console.WriteLine(message); + Console.WriteLine(exception); + } + + public void LogDebug(String message) { + Console.WriteLine(message); + } + + public void LogError(Exception exception) { + Console.WriteLine(exception); + } + + public void LogError(String message, + Exception exception) { + Console.WriteLine(message); + Console.WriteLine(exception); + } + + public void LogInformation(String message) { + Console.WriteLine(message); + } + + public void LogTrace(String message) { + Console.WriteLine(message); + } + + public void LogWarning(String message) { + Console.WriteLine(message); + } + + public Boolean IsInitialised { get; set; } + } } \ No newline at end of file diff --git a/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.DataGenerator/TransactionDataGeneratorService.cs b/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.DataGenerator/TransactionDataGeneratorService.cs index b5187c6..887adb8 100644 --- a/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.DataGenerator/TransactionDataGeneratorService.cs +++ b/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.DataGenerator/TransactionDataGeneratorService.cs @@ -1,6 +1,7 @@ using System.Net.Http.Headers; using System.Text; using Newtonsoft.Json; +using Polly; using SecurityService.Client; using SecurityService.DataTransferObjects.Responses; using Shared.Results; @@ -156,7 +157,10 @@ public async Task> PerformMerchantLogon(DateTime dateT public async Task PerformSettlement(DateTime dateTime, Guid estateId, CancellationToken cancellationToken) { - List merchants = await this.GetMerchants(estateId, cancellationToken); + Result> getMerchantsResult = await this.GetMerchants(estateId, cancellationToken); + if (getMerchantsResult.IsFailed) + return Result.Failure("Error getting merchants"); + List? merchants = getMerchantsResult.Data; List errors = new List(); foreach (MerchantResponse merchantResponse in merchants) { this.WriteTrace($"About to send Process Settlement Request for Date [{dateTime:dd-MM-yyyy}] and Estate [{estateId}] and Merchant [{merchantResponse.MerchantId}]"); @@ -379,7 +383,10 @@ private static async Task GetFileProfileIdFromOperator(String operatorName if (tokenResult.IsFailed) return ResultHelpers.CreateFailure(tokenResult); - EstateResponse estate = await this.TransactionProcessorClient.GetEstate(tokenResult.Data, merchant.EstateId, cancellationToken); + var getEstate = await this.TransactionProcessorClient.GetEstate(tokenResult.Data, merchant.EstateId, cancellationToken); + if (getEstate.IsFailed) + return Result.Failure("Get Estate failed"); + var estate = getEstate.Data; Guid userId = estate.SecurityUsers.First().SecurityUserId; Decimal depositAmount = 0; if (productType == ProductType.MobileTopup) @@ -587,7 +594,23 @@ private async Task SendProcessSettlementRequest(DateTime dateTime, Guid Result tokenResult = await this.GetAuthToken(cancellationToken); if (tokenResult.IsFailed) return ResultHelpers.CreateFailure(tokenResult); - return await this.TransactionProcessorClient.ProcessSettlement(tokenResult.Data, dateTime, estateId, merchantId, cancellationToken); + + // Create a retry policy + IAsyncPolicy policy = PolicyFactory.CreatePolicy(2, retryDelay: TimeSpan.FromSeconds(5), policyTag: "TestPolicy", null, ShouldRetryException); + + Result result = await PolicyFactory.ExecuteWithPolicyAsync(async () => + await this.TransactionProcessorClient.ProcessSettlement(tokenResult.Data, dateTime, estateId, merchantId, cancellationToken), + policy, "TransactionDataGeneratorService - SendProcessSettlementRequest"); + return result; + } + + private static bool ShouldRetryException(Exception exception) + { + return exception switch + { + TaskCanceledException { InnerException: TimeoutException } => true, + _ => false + }; } public async Task> GetMerchant(Guid estateId, diff --git a/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.DataGenerator/TransactionProcessing.SchedulerService.DataGenerator.csproj b/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.DataGenerator/TransactionProcessing.SchedulerService.DataGenerator.csproj index 1cf7235..e65dd31 100644 --- a/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.DataGenerator/TransactionProcessing.SchedulerService.DataGenerator.csproj +++ b/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.DataGenerator/TransactionProcessing.SchedulerService.DataGenerator.csproj @@ -7,10 +7,10 @@ - - - - + + + + diff --git a/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.Jobs/Jobs/Jobs.cs b/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.Jobs/Jobs/Jobs.cs index e47fec9..0900ce3 100644 --- a/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.Jobs/Jobs/Jobs.cs +++ b/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.Jobs/Jobs/Jobs.cs @@ -29,13 +29,14 @@ public static class Jobs { public static async Task GenerateMerchantStatements(ITransactionDataGeneratorService t, MerchantStatementJobConfig config, CancellationToken cancellationToken) { - List merchants = await t.GetMerchants(config.EstateId, cancellationToken); + var getMerchantsResult = await t.GetMerchants(config.EstateId, cancellationToken); - if (merchants.Any() == false) + if (getMerchantsResult.IsFailed) { return Result.Failure($"No merchants returned for Estate [{config.EstateId}]"); } + var merchants = getMerchantsResult.Data; List results = new(); foreach (MerchantResponse merchantResponse in merchants) { @@ -55,17 +56,23 @@ public static async Task GenerateMerchantStatements(ITransactionDataGene public static async Task GenerateFileUploads(ITransactionDataGeneratorService t, FileUploadJobConfig config, CancellationToken cancellationToken) { - MerchantResponse merchant = await t.GetMerchant(config.EstateId, config.MerchantId, cancellationToken); + Result merchantResult = await t.GetMerchant(config.EstateId, config.MerchantId, cancellationToken); - if (merchant == default) + if (merchantResult.IsFailed) { return Result.Failure($"No merchant returned for Estate Id [{config.EstateId}] Merchant Id [{config.MerchantId}]"); } - List contracts = await t.GetMerchantContracts(merchant, cancellationToken); + MerchantResponse merchant = merchantResult.Data; + Result> getMerchantContractsResult = await t.GetMerchantContracts(merchant, cancellationToken); + if (getMerchantContractsResult.IsFailed) + { + Console.WriteLine($"Failed to get merchant contracts: {getMerchantContractsResult.Message}"); + return Result.Failure(); + } DateTime fileDate = DateTime.Now.Date; List results = new List(); - foreach (ContractResponse contract in contracts) + foreach (ContractResponse contract in getMerchantContractsResult.Data) { if (config.ContractNames.Contains(contract.Description) == false) continue; @@ -129,19 +136,19 @@ public static async Task GenerateFloatCredits(ITransactionDataGeneratorS public static async Task GenerateTransactions(ITransactionDataGeneratorService t, TransactionJobConfig config, CancellationToken cancellationToken) { // get the merchant - var merchantResult = await t.GetMerchant(config.EstateId, config.MerchantId, cancellationToken); + Result merchantResult = await t.GetMerchant(config.EstateId, config.MerchantId, cancellationToken); if (merchantResult.IsFailed) { return Result.Failure($"Error getting Merchant Id [{config.MerchantId}] for Estate Id [{config.EstateId}]"); } - var merchant = merchantResult.Data; + MerchantResponse merchant = merchantResult.Data; DateTime transactionDate = DateTime.Now; // Get the merchants contracts - var contractResult = await t.GetMerchantContracts(merchant, cancellationToken); + Result> contractResult = await t.GetMerchantContracts(merchant, cancellationToken); if (contractResult.IsFailed) { return Result.Failure($"Error getting contracts for Merchant [{merchant.MerchantName}]"); diff --git a/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.Jobs/TransactionProcessing.SchedulerService.Jobs.csproj b/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.Jobs/TransactionProcessing.SchedulerService.Jobs.csproj index b6aa344..79995b4 100644 --- a/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.Jobs/TransactionProcessing.SchedulerService.Jobs.csproj +++ b/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.Jobs/TransactionProcessing.SchedulerService.Jobs.csproj @@ -8,10 +8,10 @@ - + - + diff --git a/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.csproj b/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.csproj index 87ce2a8..af14cf7 100644 --- a/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.csproj +++ b/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService/TransactionProcessing.SchedulerService.csproj @@ -10,7 +10,7 @@ - +