Merge pull request #3774 from NicolasDorier/wiobq

Improve performance when lot's of pending invoices
This commit is contained in:
Nicolas Dorier
2022-05-24 19:06:20 +09:00
committed by GitHub
6 changed files with 37 additions and 28 deletions

View File

@@ -297,7 +297,7 @@ namespace BTCPayServer.HostedServices
private async Task WaitPendingInvoices() private async Task WaitPendingInvoices()
{ {
await Task.WhenAll((await _invoiceRepository.GetPendingInvoices()) await Task.WhenAll((await _invoiceRepository.GetPendingInvoiceIds())
.Select(id => Wait(id)).ToArray()); .Select(id => Wait(id)).ToArray());
} }

View File

@@ -143,7 +143,7 @@ namespace BTCPayServer.Payments.Bitcoin
switch (newEvent) switch (newEvent)
{ {
case NBXplorer.Models.NewBlockEvent evt: case NBXplorer.Models.NewBlockEvent evt:
await UpdatePaymentStates(wallet, await _InvoiceRepository.GetPendingInvoices()); await UpdatePaymentStates(wallet);
_Aggregator.Publish(new Events.NewBlockEvent() { CryptoCode = evt.CryptoCode }); _Aggregator.Publish(new Events.NewBlockEvent() { CryptoCode = evt.CryptoCode });
break; break;
case NBXplorer.Models.NewTransactionEvent evt: case NBXplorer.Models.NewTransactionEvent evt:
@@ -220,9 +220,9 @@ namespace BTCPayServer.Payments.Bitcoin
} }
} }
async Task UpdatePaymentStates(BTCPayWallet wallet, string[] invoiceIds) async Task UpdatePaymentStates(BTCPayWallet wallet)
{ {
var invoices = await _InvoiceRepository.GetInvoices(invoiceIds); var invoices = await _InvoiceRepository.GetPendingInvoices(skipNoPaymentInvoices: true);
await Task.WhenAll(invoices.Select(i => UpdatePaymentStates(wallet, i)).ToArray()); await Task.WhenAll(invoices.Select(i => UpdatePaymentStates(wallet, i)).ToArray());
} }
async Task<InvoiceEntity> UpdatePaymentStates(BTCPayWallet wallet, string invoiceId) async Task<InvoiceEntity> UpdatePaymentStates(BTCPayWallet wallet, string invoiceId)
@@ -234,9 +234,9 @@ namespace BTCPayServer.Payments.Bitcoin
} }
async Task<InvoiceEntity> UpdatePaymentStates(BTCPayWallet wallet, InvoiceEntity invoice) async Task<InvoiceEntity> UpdatePaymentStates(BTCPayWallet wallet, InvoiceEntity invoice)
{ {
List<PaymentEntity> updatedPaymentEntities = new List<PaymentEntity>(); List<PaymentEntity> updatedPaymentEntities = new List<PaymentEntity>();
var transactions = await wallet.GetTransactions(invoice.GetAllBitcoinPaymentData(false) var transactions = await wallet.GetTransactions(invoice.GetAllBitcoinPaymentData(false)
.Where(p => p.Network == wallet.Network)
.Select(p => p.Outpoint.Hash) .Select(p => p.Outpoint.Hash)
.ToArray(), true); .ToArray(), true);
bool? originalPJBroadcasted = null; bool? originalPJBroadcasted = null;
@@ -355,14 +355,12 @@ namespace BTCPayServer.Payments.Bitcoin
private async Task<int> FindPaymentViaPolling(BTCPayWallet wallet, BTCPayNetwork network) private async Task<int> FindPaymentViaPolling(BTCPayWallet wallet, BTCPayNetwork network)
{ {
int totalPayment = 0; int totalPayment = 0;
var invoices = await _InvoiceRepository.GetPendingInvoices(); var invoices = await _InvoiceRepository.GetPendingInvoices(true);
var coinsPerDerivationStrategy = var coinsPerDerivationStrategy =
new Dictionary<DerivationStrategyBase, ReceivedCoin[]>(); new Dictionary<DerivationStrategyBase, ReceivedCoin[]>();
foreach (var invoiceId in invoices) foreach (var i in invoices)
{ {
var invoice = await _InvoiceRepository.GetInvoice(invoiceId, true); var invoice = i;
if (invoice == null)
continue;
var alreadyAccounted = invoice.GetAllBitcoinPaymentData(false).Select(p => p.Outpoint).ToHashSet(); var alreadyAccounted = invoice.GetAllBitcoinPaymentData(false).Select(p => p.Outpoint).ToHashSet();
var strategy = GetDerivationStrategy(invoice, network); var strategy = GetDerivationStrategy(invoice, network);
if (strategy == null) if (strategy == null)

View File

@@ -215,7 +215,7 @@ namespace BTCPayServer.Payments.Lightning
{ {
try try
{ {
var invoiceIds = await _InvoiceRepository.GetPendingInvoices(); var invoiceIds = await _InvoiceRepository.GetPendingInvoiceIds();
foreach (var invoiceId in invoiceIds) foreach (var invoiceId in invoiceIds)
_CheckInvoices.Writer.TryWrite(invoiceId); _CheckInvoices.Writer.TryWrite(invoiceId);
} }

View File

@@ -360,16 +360,11 @@ namespace BTCPayServer.Services.Altcoins.Monero.Services
private async Task UpdateAnyPendingMoneroLikePayment(string cryptoCode) private async Task UpdateAnyPendingMoneroLikePayment(string cryptoCode)
{ {
var invoiceIds = await _invoiceRepository.GetPendingInvoices(); var invoices = await _invoiceRepository.GetPendingInvoices();
if (!invoiceIds.Any()) if (!invoices.Any())
{
return; return;
}
var invoices = await _invoiceRepository.GetInvoices(new InvoiceQuery() { InvoiceId = invoiceIds });
invoices = invoices.Where(entity => entity.GetPaymentMethod(new PaymentMethodId(cryptoCode, MoneroPaymentType.Instance)) invoices = invoices.Where(entity => entity.GetPaymentMethod(new PaymentMethodId(cryptoCode, MoneroPaymentType.Instance))
?.GetPaymentMethodDetails().Activated is true).ToArray(); ?.GetPaymentMethodDetails().Activated is true).ToArray();
_logger.LogInformation($"Updating pending payments for {cryptoCode} in {string.Join(',', invoiceIds)}");
await UpdatePaymentStates(cryptoCode, invoices); await UpdatePaymentStates(cryptoCode, invoices);
} }

View File

@@ -355,16 +355,11 @@ namespace BTCPayServer.Services.Altcoins.Zcash.Services
private async Task UpdateAnyPendingZcashLikePayment(string cryptoCode) private async Task UpdateAnyPendingZcashLikePayment(string cryptoCode)
{ {
var invoiceIds = await _invoiceRepository.GetPendingInvoices(); var invoices = await _invoiceRepository.GetPendingInvoices();
if (!invoiceIds.Any()) if (!invoices.Any())
{
return; return;
}
var invoices = await _invoiceRepository.GetInvoices(new InvoiceQuery() { InvoiceId = invoiceIds });
invoices = invoices.Where(entity => entity.GetPaymentMethod(new PaymentMethodId(cryptoCode, ZcashPaymentType.Instance)) invoices = invoices.Where(entity => entity.GetPaymentMethod(new PaymentMethodId(cryptoCode, ZcashPaymentType.Instance))
?.GetPaymentMethodDetails().Activated is true).ToArray(); ?.GetPaymentMethodDetails().Activated is true).ToArray();
_logger.LogInformation($"Updating pending payments for {cryptoCode} in {string.Join(',', invoiceIds)}");
await UpdatePaymentStates(cryptoCode, invoices); await UpdatePaymentStates(cryptoCode, invoices);
} }

View File

@@ -88,7 +88,20 @@ namespace BTCPayServer.Services.Invoices
.ToListAsync()).Select(ToEntity); .ToListAsync()).Select(ToEntity);
} }
public async Task<string[]> GetPendingInvoices() public async Task<InvoiceEntity[]> GetPendingInvoices(bool includeAddressData = false, bool skipNoPaymentInvoices = false)
{
using var ctx = _applicationDbContextFactory.CreateContext();
var q = ctx.PendingInvoices.AsQueryable();
q = q.Include(o => o.InvoiceData)
.ThenInclude(o => o.Payments);
if (includeAddressData)
q = q.Include(o => o.InvoiceData)
.ThenInclude(o => o.AddressInvoices);
if (skipNoPaymentInvoices)
q = q.Where(i => i.InvoiceData.Payments.Any());
return (await q.Select(o => o.InvoiceData).ToArrayAsync()).Select(ToEntity).ToArray();
}
public async Task<string[]> GetPendingInvoiceIds()
{ {
using var ctx = _applicationDbContextFactory.CreateContext(); using var ctx = _applicationDbContextFactory.CreateContext();
return await ctx.PendingInvoices.AsQueryable().Select(data => data.Id).ToArrayAsync(); return await ctx.PendingInvoices.AsQueryable().Select(data => data.Id).ToArrayAsync();
@@ -589,8 +602,16 @@ namespace BTCPayServer.Services.Invoices
if (queryObject.InvoiceId != null && queryObject.InvoiceId.Length > 0) if (queryObject.InvoiceId != null && queryObject.InvoiceId.Length > 0)
{ {
var statusSet = queryObject.InvoiceId.ToHashSet().ToArray(); if (queryObject.InvoiceId.Length > 1)
query = query.Where(i => statusSet.Contains(i.Id)); {
var statusSet = queryObject.InvoiceId.ToHashSet().ToArray();
query = query.Where(i => statusSet.Contains(i.Id));
}
else
{
var invoiceId = queryObject.InvoiceId.First();
query = query.Where(i => i.Id == invoiceId);
}
} }
if (queryObject.StoreId != null && queryObject.StoreId.Length > 0) if (queryObject.StoreId != null && queryObject.StoreId.Length > 0)