mirror of
https://github.com/NecroticBamboo/QRBee.git
synced 2025-12-21 12:11:53 +00:00
DEEP-31 Transaction corruption anomaly added. New custom metrics added
This commit is contained in:
parent
f3979769e2
commit
ea1f2abb98
@ -18,4 +18,6 @@ internal class GeneratorSettings
|
||||
|
||||
public Anomaly LoadSpike { get; set; } = new();
|
||||
public Anomaly LargeAmount { get; set; } = new();
|
||||
public Anomaly TransactionCorruption { get; set;} = new();
|
||||
public Anomaly CoherentTransactionCorruption { get; set; } = new();
|
||||
}
|
||||
|
||||
@ -11,6 +11,7 @@ internal class LoadGenerator : IHostedService
|
||||
private readonly Client _client;
|
||||
private readonly ClientPool _clientPool;
|
||||
private readonly PaymentRequestGenerator _paymentRequestGenerator;
|
||||
private readonly TransactionDefiler _transactionDefiler;
|
||||
private readonly ILogger<LoadGenerator> _logger;
|
||||
private readonly IOptions<GeneratorSettings> _settings;
|
||||
|
||||
@ -22,6 +23,7 @@ internal class LoadGenerator : IHostedService
|
||||
QRBee.Core.Client.Client client,
|
||||
ClientPool clientPool,
|
||||
PaymentRequestGenerator paymentRequestGenerator,
|
||||
TransactionDefiler transactionDefiler,
|
||||
ILogger<LoadGenerator> logger,
|
||||
IOptions<GeneratorSettings> settings
|
||||
)
|
||||
@ -29,6 +31,7 @@ internal class LoadGenerator : IHostedService
|
||||
_client = client;
|
||||
_clientPool = clientPool;
|
||||
_paymentRequestGenerator = paymentRequestGenerator;
|
||||
_transactionDefiler = transactionDefiler;
|
||||
_logger = logger;
|
||||
_settings = settings;
|
||||
|
||||
@ -204,6 +207,8 @@ internal class LoadGenerator : IHostedService
|
||||
GatewayTransactionId = res.GatewayTransactionId
|
||||
};
|
||||
|
||||
_transactionDefiler.CorruptPaymentConfirmation(paymentConfirmation);
|
||||
|
||||
var confirmationTask = _client.ConfirmPayAsync(paymentConfirmation);
|
||||
_confirmationQueue.Add(confirmationTask);
|
||||
}
|
||||
@ -242,6 +247,8 @@ internal class LoadGenerator : IHostedService
|
||||
_rng.NextInRange(1, _settings.Value.NumberOfMerchants + 1)
|
||||
);
|
||||
|
||||
_transactionDefiler.CorruptPaymentRequest(req);
|
||||
|
||||
var resp = _client.PayAsync(req);
|
||||
|
||||
_responseQueue.Add(resp);
|
||||
|
||||
@ -30,6 +30,7 @@ builder.ConfigureServices((context, services) =>
|
||||
.Configure<GeneratorSettings>(context.Configuration.GetSection("GeneratorSettings"))
|
||||
.AddSingleton<ClientPool>()
|
||||
.AddSingleton<PaymentRequestGenerator>()
|
||||
.AddSingleton<TransactionDefiler>()
|
||||
.AddSingleton<PrivateKeyHandlerFactory>(x => no => new PrivateKeyHandler(x.GetRequiredService<ILogger<ServerPrivateKeyHandler>>(), x.GetRequiredService<IConfiguration>(), no))
|
||||
.AddSingleton<SecurityServiceFactory>(x => no => new AndroidSecurityService(x.GetRequiredService<PrivateKeyHandlerFactory>()(no)))
|
||||
.AddHostedService<LoadGenerator>()
|
||||
|
||||
84
QRBee.Load.Generator/TransactionDefiler.cs
Normal file
84
QRBee.Load.Generator/TransactionDefiler.cs
Normal file
@ -0,0 +1,84 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using QRBee.Core.Data;
|
||||
|
||||
namespace QRBee.Load.Generator
|
||||
{
|
||||
internal class TransactionDefiler
|
||||
{
|
||||
private readonly ILogger<TransactionDefiler> _logger;
|
||||
private ThreadSafeRandom _rng = new ThreadSafeRandom();
|
||||
private double _corruptionProbability;
|
||||
private double _coherentCorruptionProbability;
|
||||
private bool _multipleCorruption = false;
|
||||
private int _sequenceLengthMin;
|
||||
private int _sequenceLengthMax;
|
||||
private int _sequenceLength;
|
||||
private int _corruptionCounter = 0;
|
||||
|
||||
public TransactionDefiler(IOptions<GeneratorSettings> settings, ILogger<TransactionDefiler> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
|
||||
var transactionCorruption = settings.Value.TransactionCorruption;
|
||||
_corruptionProbability = transactionCorruption.Probability;
|
||||
|
||||
var coherentTransactionCorruption = settings.Value.CoherentTransactionCorruption;
|
||||
_coherentCorruptionProbability = coherentTransactionCorruption.Probability;
|
||||
if (_coherentCorruptionProbability > 0)
|
||||
{
|
||||
if (coherentTransactionCorruption.Parameters.TryGetValue("SequenceLengthMin", out var s))
|
||||
_sequenceLengthMin = int.Parse(s);
|
||||
if (coherentTransactionCorruption.Parameters.TryGetValue("SequenceLengthMax", out s))
|
||||
_sequenceLengthMax = int.Parse(s);
|
||||
}
|
||||
|
||||
|
||||
_logger.LogDebug($"Transaction corruption configured: Probability={_corruptionProbability}");
|
||||
_logger.LogDebug($"Coherent transaction corruption configured: Probability={_coherentCorruptionProbability}, SequenceLengthMin={_sequenceLengthMin}, SequenceLengthMax={_sequenceLengthMax}");
|
||||
}
|
||||
|
||||
public void CorruptPaymentRequest(PaymentRequest paymentRequest)
|
||||
{
|
||||
var dice = _rng.NextDouble();
|
||||
if(_multipleCorruption)
|
||||
{
|
||||
_corruptionCounter++;
|
||||
_logger.LogWarning($"Anomaly: Coherent corrupted transaction Dice={dice}, Corruption counter = {_corruptionCounter}, Sequence length = {_sequenceLength}");
|
||||
paymentRequest.ClientResponse.MerchantRequest.Amount += 0.01M;
|
||||
|
||||
if (_corruptionCounter >= _sequenceLength)
|
||||
{
|
||||
_corruptionCounter = 0;
|
||||
_multipleCorruption = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (dice < _corruptionProbability)
|
||||
{
|
||||
_logger.LogWarning($"Anomaly: Corrupted transaction Dice={dice}");
|
||||
paymentRequest.ClientResponse.MerchantRequest.Amount += 10M;
|
||||
|
||||
if(dice < _coherentCorruptionProbability && _multipleCorruption==false)
|
||||
{
|
||||
_sequenceLength = _rng.NextInRange(_sequenceLengthMin,_sequenceLengthMax);
|
||||
_multipleCorruption = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void CorruptPaymentConfirmation(PaymentConfirmation paymentConfirmation)
|
||||
{
|
||||
var dice = _rng.NextDouble();
|
||||
if (dice < _corruptionProbability)
|
||||
{
|
||||
_logger.LogWarning($"Anomaly: Corrupted transaction confirmation Dice={dice}");
|
||||
paymentConfirmation.GatewayTransactionId = "BadGatewayTransactionId";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -14,22 +14,37 @@
|
||||
"GeneratorSettings": {
|
||||
"NumberOfClients": 100,
|
||||
"NumberOfMerchants": 10,
|
||||
"NumberOfThreads": 10,
|
||||
"DelayBetweenMessagesMSec": 300,
|
||||
"NumberOfThreads": 5,
|
||||
"DelayBetweenMessagesMSec": 500,
|
||||
"DelayJitterMSec": 50,
|
||||
"MinAmount": 10,
|
||||
"MaxAmount": 100,
|
||||
|
||||
"LoadSpike": {
|
||||
"Probability": 0.001,
|
||||
"Probability": 0.004,
|
||||
"Parameters": {
|
||||
"Duration": "00:00:15",
|
||||
"Delay": "00:00:00.0100000"
|
||||
}
|
||||
},
|
||||
|
||||
"TransactionCorruption": {
|
||||
"Probability": 0.004,
|
||||
"Parameters": {
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
"CoherentTransactionCorruption": {
|
||||
"Probability": 0.002,
|
||||
"Parameters": {
|
||||
"SequenceLengthMin": 2,
|
||||
"SequenceLengthMax": 10
|
||||
}
|
||||
},
|
||||
|
||||
"LargeAmount": {
|
||||
"Probability": 0.03,
|
||||
"Probability": 0.003,
|
||||
"Parameters": {
|
||||
"Value": "1000"
|
||||
}
|
||||
|
||||
@ -37,11 +37,19 @@
|
||||
</layout>
|
||||
</appender>
|
||||
|
||||
<appender name="RollingFile" type="log4net.Appender.RollingFileAppender">
|
||||
<file value="log-file.txt" />
|
||||
<appendToFile value="false" />
|
||||
<layout type="log4net.Layout.PatternLayout">
|
||||
<conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />
|
||||
</layout>
|
||||
</appender>
|
||||
|
||||
<appender name="BufferingForwardingAppender" type="log4net.Appender.BufferingForwardingAppender" >
|
||||
<bufferSize value="1"/>
|
||||
<appender-ref ref="DebugAppender" />
|
||||
<appender-ref ref="Console" />
|
||||
<!-- <appender-ref ref="RollingFile" /> -->
|
||||
<appender-ref ref="RollingFile" />
|
||||
</appender>
|
||||
|
||||
<logger name="System.Net.Http">
|
||||
|
||||
@ -8,6 +8,9 @@ namespace QRBee.Api.Services
|
||||
private Counter<int> MerchantResponseCounter { get; }
|
||||
private Counter<int> SucceededTransactionsCounter { get; }
|
||||
private Counter<int> FailedTransactionsCounter { get; }
|
||||
private Counter<int> CorruptTransactionsCounter { get; }
|
||||
private Counter<int> SucceededPaymentConfirmationsCounter { get; }
|
||||
private Counter<int> FailedPaymentConfirmationsCounter { get; }
|
||||
private Counter<long> TotalCreditCardCheckTime { get; }
|
||||
private Counter<long> TotalPaymentTime { get; }
|
||||
|
||||
@ -20,11 +23,16 @@ namespace QRBee.Api.Services
|
||||
|
||||
MerchantRequestCounter = meter.CreateCounter<int>("merchant-requests", description: "Merchant has sent a request");
|
||||
MerchantResponseCounter = meter.CreateCounter<int>("merchant-responses");
|
||||
|
||||
SucceededTransactionsCounter = meter.CreateCounter<int>("transaction-succeeded", description: "Transaction succeeded");
|
||||
FailedTransactionsCounter = meter.CreateCounter<int>("transaction-failed", description: "Transaction failed");
|
||||
CorruptTransactionsCounter = meter.CreateCounter<int>("transaction-corrupt", description: "Transaction was corrupted");
|
||||
|
||||
TotalCreditCardCheckTime = meter.CreateCounter<long>("Total-credit-card-check-time","msec");
|
||||
TotalPaymentTime = meter.CreateCounter<long>("Total-payment-time","msec");
|
||||
SucceededPaymentConfirmationsCounter = meter.CreateCounter<int>("payment-confirmation-succeeded", description: "Payment confirmation succeeded");
|
||||
FailedPaymentConfirmationsCounter = meter.CreateCounter<int>("payment-confirmation-failed", description: "Payment confirmation failed");
|
||||
|
||||
TotalCreditCardCheckTime = meter.CreateCounter<long>("total-credit-card-check-time","msec");
|
||||
TotalPaymentTime = meter.CreateCounter<long>("total-payment-time","msec");
|
||||
}
|
||||
|
||||
|
||||
@ -32,6 +40,9 @@ namespace QRBee.Api.Services
|
||||
public void AddMerchantResponse() => MerchantResponseCounter.Add(1);
|
||||
public void AddSucceededTransaction() => SucceededTransactionsCounter.Add(1);
|
||||
public void AddFailedTransaction() => FailedTransactionsCounter.Add(1);
|
||||
public void AddCorruptTransaction() => CorruptTransactionsCounter.Add(1);
|
||||
public void AddSucceededPaymentConfirmation() => SucceededPaymentConfirmationsCounter.Add(1);
|
||||
public void AddFailedPaymentConfirmation() => FailedPaymentConfirmationsCounter.Add(1);
|
||||
public void AddTotalCreditCardCheckTime(long milliseconds) => TotalCreditCardCheckTime.Add(milliseconds);
|
||||
public void AddTotalPaymentTime(long milliseconds) => TotalPaymentTime.Add(milliseconds);
|
||||
|
||||
|
||||
@ -172,8 +172,17 @@ namespace QRBee.Api.Services
|
||||
var t4 = CheckTransaction(tid);
|
||||
|
||||
//Parallel task execution
|
||||
try
|
||||
{
|
||||
await Task.WhenAll(t2, t3, t4);
|
||||
_logger.LogInformation($"Transaction=\"{tid}\" Fully validated");
|
||||
}
|
||||
catch(Exception)
|
||||
{
|
||||
_customMetrics.AddCorruptTransaction();
|
||||
throw;
|
||||
}
|
||||
|
||||
|
||||
//5. Decrypt client card data
|
||||
var creditCardCheckTime = Stopwatch.StartNew();
|
||||
@ -206,17 +215,17 @@ namespace QRBee.Api.Services
|
||||
//9. Record transaction with result
|
||||
if (gatewayResponse.Success)
|
||||
{
|
||||
_customMetrics.AddSucceededTransaction();
|
||||
|
||||
info.Status=TransactionInfo.TransactionStatus.Succeeded;
|
||||
info.GatewayTransactionId=gatewayResponse.GatewayTransactionId;
|
||||
|
||||
_customMetrics.AddSucceededTransaction();
|
||||
}
|
||||
else
|
||||
{
|
||||
_customMetrics.AddFailedTransaction();
|
||||
|
||||
info.Status = TransactionInfo.TransactionStatus.Rejected;
|
||||
info.RejectReason = gatewayResponse.ErrorMessage;
|
||||
|
||||
_customMetrics.AddFailedTransaction();
|
||||
}
|
||||
await _storage.UpdateTransaction(info);
|
||||
_logger.LogInformation($"Transaction=\"{tid}\" complete Status=\"{info.Status}\"");
|
||||
@ -403,9 +412,11 @@ namespace QRBee.Api.Services
|
||||
trans.Status = TransactionInfo.TransactionStatus.Confirmed;
|
||||
await _storage.UpdateTransaction(trans);
|
||||
_logger.LogInformation($"Transaction with MerchantTransactionId: {trans.MerchantTransactionId} confirmed");
|
||||
_customMetrics.AddSucceededPaymentConfirmation();
|
||||
}
|
||||
else
|
||||
{
|
||||
_customMetrics.AddFailedPaymentConfirmation();
|
||||
throw new ApplicationException($"Transaction with gatewayTransactionId:{value.GatewayTransactionId} failed.");
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user