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
commit e7180ac82a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 37 additions and 28 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -88,7 +88,20 @@ namespace BTCPayServer.Services.Invoices
.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();
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)
{
var statusSet = queryObject.InvoiceId.ToHashSet().ToArray();
query = query.Where(i => statusSet.Contains(i.Id));
if (queryObject.InvoiceId.Length > 1)
{
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)