Skip to content

Commit

Permalink
payment: limit number of queries when processing payments
Browse files Browse the repository at this point in the history
Use the new "return rehydrated object upon create or update" mechanism to
avoid unnecessary get queries.

Signed-off-by: Pierre-Alexandre Meyer <pierre@mouraf.org>
  • Loading branch information
pierre committed Mar 31, 2017
1 parent c9e306e commit ac9ffc6
Show file tree
Hide file tree
Showing 13 changed files with 171 additions and 90 deletions.
Expand Up @@ -225,14 +225,15 @@ public Payment apply(final PaymentModelDao paymentModelDao) {

public Payment getPayment(final UUID paymentId, final boolean withPluginInfo, final boolean withAttempts, final Iterable<PluginProperty> properties, final TenantContext tenantContext, final InternalTenantContext internalTenantContext) throws PaymentApiException {
final PaymentModelDao paymentModelDao = paymentDao.getPayment(paymentId, internalTenantContext);
if (paymentModelDao == null) {
return null;
}
return toPayment(paymentModelDao, withPluginInfo, withAttempts, properties, tenantContext, internalTenantContext);
return getPayment(paymentModelDao, withPluginInfo, withAttempts, properties, tenantContext, internalTenantContext);
}

public Payment getPaymentByExternalKey(final String paymentExternalKey, final boolean withPluginInfo, final boolean withAttempts, final Iterable<PluginProperty> properties, final TenantContext tenantContext, final InternalTenantContext internalTenantContext) throws PaymentApiException {
final PaymentModelDao paymentModelDao = paymentDao.getPaymentByExternalKey(paymentExternalKey, internalTenantContext);
return getPayment(paymentModelDao, withPluginInfo, withAttempts, properties, tenantContext, internalTenantContext);
}

private Payment getPayment(final PaymentModelDao paymentModelDao, final boolean withPluginInfo, final boolean withAttempts, final Iterable<PluginProperty> properties, final TenantContext tenantContext, final InternalTenantContext internalTenantContext) throws PaymentApiException {
if (paymentModelDao == null) {
return null;
}
Expand Down Expand Up @@ -546,9 +547,9 @@ public boolean apply(final PaymentTransactionModelDao input) {
currentStateName = paymentModelDao.getLastSuccessStateName();
}

final UUID nonNullPaymentId = paymentAutomatonRunner.run(paymentStateContext, daoHelper, currentStateName, transactionType);
paymentAutomatonRunner.run(paymentStateContext, daoHelper, currentStateName, transactionType);

return getPayment(nonNullPaymentId, true, false, properties, callContext, internalCallContext);
return getPayment(paymentStateContext.getPaymentModelDao(), true, false, properties, callContext, internalCallContext);
}

private void runSanityOnTransactionExternalKey(final Iterable<PaymentTransactionModelDao> allPaymentTransactionsForKey,
Expand Down
Expand Up @@ -31,6 +31,7 @@
import org.killbill.billing.payment.api.TransactionStatus;
import org.killbill.billing.payment.api.TransactionType;
import org.killbill.billing.payment.core.PaymentPluginServiceRegistration;
import org.killbill.billing.payment.dao.PaymentAndTransactionModelDao;
import org.killbill.billing.payment.dao.PaymentDao;
import org.killbill.billing.payment.dao.PaymentMethodModelDao;
import org.killbill.billing.payment.dao.PaymentModelDao;
Expand Down Expand Up @@ -86,8 +87,8 @@ public void createNewPaymentTransaction() throws PaymentApiException {
final PaymentTransactionModelDao newPaymentTransactionModelDao = buildNewPaymentTransactionModelDao(newPaymentModelDao.getId());

existingTransactions = ImmutableList.of();
final PaymentModelDao paymentModelDao = paymentDao.insertPaymentWithFirstTransaction(newPaymentModelDao, newPaymentTransactionModelDao, internalCallContext);
paymentTransactionModelDao = paymentDao.getTransactionsForPayment(paymentModelDao.getId(), internalCallContext).get(0);
final PaymentAndTransactionModelDao paymentAndTransactionModelDao = paymentDao.insertPaymentWithFirstTransaction(newPaymentModelDao, newPaymentTransactionModelDao, internalCallContext);
paymentTransactionModelDao = paymentAndTransactionModelDao.getPaymentTransactionModelDao();

} else {
existingTransactions = paymentDao.getTransactionsForPayment(paymentStateContext.getPaymentId(), internalCallContext);
Expand Down Expand Up @@ -131,22 +132,22 @@ public void processPaymentInfoPlugin(final TransactionStatus transactionStatus,
final String gatewayErrorMsg = paymentInfoPlugin == null ? null : paymentInfoPlugin.getGatewayError();

final String lastSuccessPaymentState = paymentSMHelper.isSuccessState(currentPaymentStateName) ? currentPaymentStateName : null;
paymentDao.updatePaymentAndTransactionOnCompletion(paymentStateContext.getAccount().getId(),
paymentStateContext.getAttemptId(),
paymentStateContext.getPaymentId(),
paymentStateContext.getTransactionType(),
currentPaymentStateName,
lastSuccessPaymentState,
paymentStateContext.getPaymentTransactionModelDao().getId(),
transactionStatus,
processedAmount,
processedCurrency,
gatewayErrorCode,
gatewayErrorMsg,
internalCallContext);

final PaymentAndTransactionModelDao paymentAndTransactionModelDao = paymentDao.updatePaymentAndTransactionOnCompletion(paymentStateContext.getAccount().getId(),
paymentStateContext.getAttemptId(),
paymentStateContext.getPaymentId(),
paymentStateContext.getTransactionType(),
currentPaymentStateName,
lastSuccessPaymentState,
paymentStateContext.getPaymentTransactionModelDao().getId(),
transactionStatus,
processedAmount,
processedCurrency,
gatewayErrorCode,
gatewayErrorMsg,
internalCallContext);
// Update the context
paymentStateContext.setPaymentTransactionModelDao(paymentDao.getPaymentTransaction(paymentStateContext.getPaymentTransactionModelDao().getId(), internalCallContext));
paymentStateContext.setPaymentModelDao(paymentAndTransactionModelDao.getPaymentModelDao());
paymentStateContext.setPaymentTransactionModelDao(paymentAndTransactionModelDao.getPaymentTransactionModelDao());
}

public String getPaymentProviderPluginName(final boolean includeDeleted) throws PaymentApiException {
Expand Down
Expand Up @@ -160,7 +160,7 @@ public PaymentAutomatonDAOHelper buildDaoHelper(final PaymentStateContext paymen
return new PaymentAutomatonDAOHelper(paymentStateContext, utcNow, paymentDao, paymentPluginServiceRegistration, internalCallContext, eventBus, paymentSMHelper);
}

public UUID run(final PaymentStateContext paymentStateContext,
public void run(final PaymentStateContext paymentStateContext,
final PaymentAutomatonDAOHelper daoHelper,
@Nullable final String currentStateNameOrNull,
final TransactionType transactionType) throws PaymentApiException {
Expand Down Expand Up @@ -214,8 +214,6 @@ public UUID run(final PaymentStateContext paymentStateContext,
}

runStateMachineOperation(currentStateName, transactionType, leavingStateCallback, operationCallback, enteringStateCallback, includeDeletedPaymentMethod, paymentStateContext, daoHelper);

return paymentStateContext.getPaymentId();
}

//
Expand Down
@@ -1,6 +1,6 @@
/*
* Copyright 2014-2015 Groupon, Inc
* Copyright 2014-2015 The Billing Project, LLC
* Copyright 2014-2017 Groupon, Inc
* Copyright 2014-2017 The Billing Project, LLC
*
* The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
Expand Down Expand Up @@ -29,6 +29,7 @@
import org.killbill.billing.catalog.api.Currency;
import org.killbill.billing.payment.api.PluginProperty;
import org.killbill.billing.payment.api.TransactionType;
import org.killbill.billing.payment.dao.PaymentModelDao;
import org.killbill.billing.payment.dao.PaymentTransactionModelDao;
import org.killbill.billing.payment.plugin.api.PaymentTransactionInfoPlugin;
import org.killbill.billing.util.callcontext.CallContext;
Expand All @@ -38,7 +39,7 @@

public class PaymentStateContext {


private PaymentModelDao paymentModelDao;
// The following fields (paymentId, transactionId, amount, currency) may take their value from the paymentTransactionModelDao *when they are not already set*
private PaymentTransactionModelDao paymentTransactionModelDao;
// Initialized in CTOR or only set through paymentTransactionModelDao
Expand Down Expand Up @@ -119,6 +120,14 @@ public void setPaymentMethodId(final UUID paymentMethodId) {
this.paymentMethodId = paymentMethodId;
}

public PaymentModelDao getPaymentModelDao() {
return paymentModelDao;
}

public void setPaymentModelDao(final PaymentModelDao paymentModelDao) {
this.paymentModelDao = paymentModelDao;
}

public PaymentTransactionModelDao getPaymentTransactionModelDao() {
return paymentTransactionModelDao;
}
Expand Down
Expand Up @@ -288,19 +288,22 @@ private List<String> expandSearchFilterToStateNames(final String searchKey) {
}

@Override
public PaymentModelDao insertPaymentWithFirstTransaction(final PaymentModelDao payment, final PaymentTransactionModelDao paymentTransaction, final InternalCallContext context) {
public PaymentAndTransactionModelDao insertPaymentWithFirstTransaction(final PaymentModelDao payment, final PaymentTransactionModelDao paymentTransaction, final InternalCallContext context) {
final PaymentAndTransactionModelDao paymentAndTransactionModelDao = new PaymentAndTransactionModelDao();

return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<PaymentModelDao>() {
return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<PaymentAndTransactionModelDao>() {

@Override
public PaymentModelDao inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
public PaymentAndTransactionModelDao inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
final PaymentSqlDao paymentSqlDao = entitySqlDaoWrapperFactory.become(PaymentSqlDao.class);
final PaymentModelDao paymentModelDao = createAndRefresh(paymentSqlDao, payment, context);
paymentAndTransactionModelDao.setPaymentModelDao(paymentModelDao);

final TransactionSqlDao transactionSqlDao = entitySqlDaoWrapperFactory.become(TransactionSqlDao.class);
createAndRefresh(transactionSqlDao, paymentTransaction, context);
final PaymentTransactionModelDao paymentTransactionModelDao = createAndRefresh(transactionSqlDao, paymentTransaction, context);
paymentAndTransactionModelDao.setPaymentTransactionModelDao(paymentTransactionModelDao);

return paymentModelDao;
return paymentAndTransactionModelDao;
}
});
}
Expand All @@ -321,34 +324,50 @@ public PaymentTransactionModelDao inTransaction(final EntitySqlDaoWrapperFactory
}

@Override
public void updatePaymentAndTransactionOnCompletion(final UUID accountId, @Nullable final UUID attemptId, final UUID paymentId, final TransactionType transactionType,
final String currentPaymentStateName, @Nullable final String lastPaymentSuccessStateName,
final UUID transactionId, final TransactionStatus transactionStatus,
final BigDecimal processedAmount, final Currency processedCurrency,
final String gatewayErrorCode, final String gatewayErrorMsg,
final InternalCallContext context) {
transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
public PaymentAndTransactionModelDao updatePaymentAndTransactionOnCompletion(final UUID accountId, @Nullable final UUID attemptId, final UUID paymentId, final TransactionType transactionType,
final String currentPaymentStateName, @Nullable final String lastPaymentSuccessStateName,
final UUID transactionId, final TransactionStatus transactionStatus,
final BigDecimal processedAmount, final Currency processedCurrency,
final String gatewayErrorCode, final String gatewayErrorMsg,
final InternalCallContext context) {
final PaymentAndTransactionModelDao paymentAndTransactionModelDao = new PaymentAndTransactionModelDao();

return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<PaymentAndTransactionModelDao>() {

@Override
public Void inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
public PaymentAndTransactionModelDao inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
final InternalCallContext contextWithUpdatedDate = contextWithUpdatedDate(context);

final TransactionSqlDao transactional = entitySqlDaoWrapperFactory.become(TransactionSqlDao.class);
final PaymentTransactionModelDao paymentTransactionModelDao = transactional.getById(transactionId.toString(), context);
transactional.updateTransactionStatus(transactionId.toString(),
attemptId == null ? (paymentTransactionModelDao.getAttemptId() == null ? null : paymentTransactionModelDao.getAttemptId().toString()) : attemptId.toString(),
processedAmount,
processedCurrency == null ? null : processedCurrency.toString(),
transactionStatus == null ? null : transactionStatus.toString(),
gatewayErrorCode,
gatewayErrorMsg,
contextWithUpdatedDate);
final String updatedAttemptId;
if (attemptId == null) {
final PaymentTransactionModelDao paymentTransactionModelDao = transactional.getById(transactionId.toString(), context);
updatedAttemptId = paymentTransactionModelDao.getAttemptId() == null ? null : paymentTransactionModelDao.getAttemptId().toString();
} else {
updatedAttemptId = attemptId.toString();
}
final PaymentTransactionModelDao paymentTransactionModelDao = (PaymentTransactionModelDao) transactional.updateTransactionStatus(transactionId.toString(),
updatedAttemptId,
processedAmount,
processedCurrency == null ? null : processedCurrency.toString(),
transactionStatus == null ? null : transactionStatus.toString(),
gatewayErrorCode,
gatewayErrorMsg,
contextWithUpdatedDate);
paymentAndTransactionModelDao.setPaymentTransactionModelDao(paymentTransactionModelDao);

final PaymentSqlDao paymentSqlDao = entitySqlDaoWrapperFactory.become(PaymentSqlDao.class);
final PaymentModelDao paymentModelDao;
if (lastPaymentSuccessStateName != null) {
entitySqlDaoWrapperFactory.become(PaymentSqlDao.class).updateLastSuccessPaymentStateName(paymentId.toString(), currentPaymentStateName, lastPaymentSuccessStateName, contextWithUpdatedDate);
paymentModelDao = (PaymentModelDao) paymentSqlDao.updateLastSuccessPaymentStateName(paymentId.toString(), currentPaymentStateName, lastPaymentSuccessStateName, contextWithUpdatedDate);
} else {
entitySqlDaoWrapperFactory.become(PaymentSqlDao.class).updatePaymentStateName(paymentId.toString(), currentPaymentStateName, contextWithUpdatedDate);
paymentModelDao = (PaymentModelDao) paymentSqlDao.updatePaymentStateName(paymentId.toString(), currentPaymentStateName, contextWithUpdatedDate);
}
paymentAndTransactionModelDao.setPaymentModelDao(paymentModelDao);

postPaymentEventFromTransaction(accountId, transactionStatus, transactionType, paymentId, transactionId, processedAmount, processedCurrency, clock.getUTCNow(), gatewayErrorCode, entitySqlDaoWrapperFactory, context);
return null;

return paymentAndTransactionModelDao;
}
});
}
Expand Down

1 comment on commit ac9ffc6

@sbrossie
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Please sign in to comment.