use of org.killbill.commons.locker.GlobalLock in project killbill by killbill.
the class OverdueWrapper method clear.
public void clear(final DateTime effectiveDate, final InternalCallContext context) throws OverdueException, OverdueApiException {
GlobalLock lock = null;
try {
lock = locker.lockWithNumberOfTries(LockerType.ACCNT_INV_PAY.toString(), overdueable.getId().toString(), MAX_LOCK_RETRIES);
clearWithLock(effectiveDate, context);
} catch (final LockFailedException e) {
log.warn("Failed to clear overdue for accountId='{}'", overdueable.getId(), e);
} finally {
if (lock != null) {
lock.release();
}
}
}
use of org.killbill.commons.locker.GlobalLock in project killbill by killbill.
the class InvoiceDispatcher method processAccount.
public Invoice processAccount(final boolean isApiCall, final UUID accountId, @Nullable final LocalDate targetDate, @Nullable final DryRunArguments dryRunArguments, final boolean isRescheduled, final InternalCallContext context) throws InvoiceApiException {
boolean parkedAccount = false;
try {
parkedAccount = parkedAccountsManager.isParked(context);
if (parkedAccount && !isApiCall) {
log.warn("Ignoring invoice generation process for accountId='{}', targetDate='{}', account is parked", accountId.toString(), targetDate);
return null;
}
} catch (final TagApiException e) {
log.warn("Unable to determine parking state for accountId='{}'", accountId);
}
if (!isApiCall && !locker.isFree(LockerType.ACCNT_INV_PAY.toString(), accountId.toString())) {
if (invoiceOptimizer.rescheduleProcessAccount(accountId, context)) {
return null;
}
}
GlobalLock lock = null;
try {
// Grab lock unless we do a dry-run
final boolean isDryRun = dryRunArguments != null;
lock = !isDryRun ? locker.lockWithNumberOfTries(LockerType.ACCNT_INV_PAY.toString(), accountId.toString(), invoiceConfig.getMaxGlobalLockRetries()) : null;
return processAccountInternal(isApiCall, parkedAccount, accountId, targetDate, dryRunArguments, isRescheduled, context);
} catch (final LockFailedException e) {
if (isApiCall) {
throw new InvoiceApiException(e, ErrorCode.UNEXPECTED_ERROR, "Failed to generate invoice: failed to acquire lock");
}
if (!invoiceOptimizer.rescheduleProcessAccount(accountId, context)) {
log.warn("Failed to process invoice for accountId='{}', targetDate='{}'", accountId.toString(), targetDate, e);
}
} finally {
if (lock != null) {
lock.release();
}
}
return null;
}
use of org.killbill.commons.locker.GlobalLock in project killbill by killbill.
the class InvoiceApiHelper method dispatchToInvoicePluginsAndInsertItems.
@SuppressFBWarnings("NP_ALWAYS_NULL_EXCEPTION")
public List<InvoiceItem> dispatchToInvoicePluginsAndInsertItems(final UUID accountId, final boolean isDryRun, final WithAccountLock withAccountLock, final LinkedList<PluginProperty> properties, final CallContext contextMaybeWithoutAccountId) throws InvoiceApiException {
// Invoked by User API call
final LocalDate targetDate = null;
final List<Invoice> existingInvoices = null;
final boolean isRescheduled = false;
final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(accountId, contextMaybeWithoutAccountId);
final CallContext context = internalCallContextFactory.createCallContext(internalCallContext);
final DateTime rescheduleDate = invoicePluginDispatcher.priorCall(targetDate, existingInvoices, isDryRun, isRescheduled, context, properties, internalCallContext);
if (rescheduleDate != null) {
throw new InvoiceApiException(ErrorCode.INVOICE_PLUGIN_API_ABORTED, "delayed scheduling is unsupported for API calls");
}
boolean success = false;
GlobalLock lock = null;
Iterable<DefaultInvoice> invoicesForPlugins = null;
try {
lock = locker.lockWithNumberOfTries(LockerType.ACCNT_INV_PAY.toString(), accountId.toString(), invoiceConfig.getMaxGlobalLockRetries());
invoicesForPlugins = withAccountLock.prepareInvoices();
final List<InvoiceModelDao> invoiceModelDaos = new LinkedList<InvoiceModelDao>();
for (final DefaultInvoice invoiceForPlugin : invoicesForPlugins) {
// Call plugin(s)
invoicePluginDispatcher.updateOriginalInvoiceWithPluginInvoiceItems(invoiceForPlugin, isDryRun, context, properties, internalCallContext);
// Transformation to InvoiceModelDao
final InvoiceModelDao invoiceModelDao = new InvoiceModelDao(invoiceForPlugin);
final List<InvoiceItem> invoiceItems = invoiceForPlugin.getInvoiceItems();
final List<InvoiceItemModelDao> invoiceItemModelDaos = toInvoiceItemModelDao(invoiceItems);
invoiceModelDao.addInvoiceItems(invoiceItemModelDaos);
// Keep track of modified invoices
invoiceModelDaos.add(invoiceModelDao);
}
final List<InvoiceItemModelDao> createdInvoiceItems = dao.createInvoices(invoiceModelDaos, null, ImmutableSet.of(), internalCallContext);
success = true;
return fromInvoiceItemModelDao(createdInvoiceItems);
} catch (final LockFailedException e) {
throw new InvoiceApiException(e, ErrorCode.UNEXPECTED_ERROR, "Failed to process invoice items: failed to acquire lock");
} finally {
if (lock != null) {
lock.release();
}
if (success) {
for (final Invoice invoiceForPlugin : invoicesForPlugins) {
final DefaultInvoice refreshedInvoice = new DefaultInvoice(dao.getById(invoiceForPlugin.getId(), internalCallContext));
invoicePluginDispatcher.onSuccessCall(targetDate, refreshedInvoice, existingInvoices, isDryRun, isRescheduled, context, properties, internalCallContext);
}
} else {
invoicePluginDispatcher.onFailureCall(targetDate, null, existingInvoices, isDryRun, isRescheduled, context, properties, internalCallContext);
}
}
}
use of org.killbill.commons.locker.GlobalLock in project killbill by killbill.
the class TestIncompletePaymentTransactionTaskWithDB method testHandleLockExceptions.
@Test(groups = "slow", description = "https://github.com/killbill/killbill/issues/675")
public void testHandleLockExceptions() throws PaymentApiException {
final Payment payment = paymentApi.createPurchase(account, account.getPaymentMethodId(), null, BigDecimal.TEN, Currency.EUR, null, UUID.randomUUID().toString(), UUID.randomUUID().toString(), ImmutableList.<PluginProperty>of(new PluginProperty(MockPaymentProviderPlugin.PLUGIN_PROPERTY_PAYMENT_PLUGIN_STATUS_OVERRIDE, PaymentPluginStatus.PENDING.toString(), false)), callContext);
final UUID transactionId = payment.getTransactions().get(0).getId();
final JanitorNotificationKey notificationKey = new JanitorNotificationKey(transactionId, incompletePaymentTransactionTask.getClass().toString(), true, 1);
final UUID userToken = UUID.randomUUID();
Assert.assertTrue(Iterables.isEmpty(incompletePaymentAttemptTask.janitorQueue.getFutureNotificationForSearchKeys(internalCallContext.getAccountRecordId(), internalCallContext.getTenantRecordId())));
GlobalLock lock = null;
try {
lock = locker.lockWithNumberOfTries(LockerType.ACCNT_INV_PAY.toString(), account.getId().toString(), paymentConfig.getMaxGlobalLockRetries());
incompletePaymentAttemptTask.processNotification(notificationKey, userToken, internalCallContext.getAccountRecordId(), internalCallContext.getTenantRecordId());
final Iterable<NotificationEventWithMetadata<NotificationEvent>> futureNotifications = incompletePaymentAttemptTask.janitorQueue.getFutureNotificationForSearchKeys(internalCallContext.getAccountRecordId(), internalCallContext.getTenantRecordId());
Assert.assertFalse(Iterables.isEmpty(futureNotifications));
final NotificationEventWithMetadata<NotificationEvent> notificationEventWithMetadata = ImmutableList.<NotificationEventWithMetadata<NotificationEvent>>copyOf(futureNotifications).get(0);
Assert.assertEquals(notificationEventWithMetadata.getUserToken(), userToken);
Assert.assertEquals(notificationEventWithMetadata.getEvent().getClass(), JanitorNotificationKey.class);
final JanitorNotificationKey event = (JanitorNotificationKey) notificationEventWithMetadata.getEvent();
Assert.assertEquals(event.getUuidKey(), transactionId);
Assert.assertEquals((int) event.getAttemptNumber(), 2);
// Based on config "1h, 1d"
Assert.assertTrue(notificationEventWithMetadata.getEffectiveDate().compareTo(clock.getUTCNow().plusDays(1).plusSeconds(5)) < 0);
} catch (final LockFailedException e) {
Assert.fail();
} finally {
if (lock != null) {
lock.release();
}
}
}
use of org.killbill.commons.locker.GlobalLock in project killbill by killbill.
the class TestRetryablePayment method testRetryLogicFromRetriedStateWithLockFailure.
@Test(groups = "fast")
public void testRetryLogicFromRetriedStateWithLockFailure() throws LockFailedException {
GlobalLock lock = null;
try {
// Grab lock so that operation later will fail...
lock = locker.lockWithNumberOfTries(LockerType.ACCNT_INV_PAY.toString(), account.getId().toString(), 1);
mockRetryProviderPlugin.setAborted(false).setNextRetryDate(null);
mockRetryAuthorizeOperationCallback.setResult(OperationResult.SUCCESS).setException(null);
runner.setOperationCallback(mockRetryAuthorizeOperationCallback).setContext(paymentStateContext);
final State state = retrySMHelper.getRetriedState();
final UUID transactionId = UUID.randomUUID();
final UUID paymentId = UUID.randomUUID();
final PaymentAttemptModelDao attempt = new PaymentAttemptModelDao(account.getId(), paymentMethodId, utcNow, utcNow, paymentExternalKey, transactionId, paymentTransactionExternalKey, TransactionType.AUTHORIZE, state.getName(), amount, currency, null, EMPTY_PROPERTIES);
paymentDao.insertPaymentAttemptWithProperties(attempt, internalCallContext);
paymentDao.insertPaymentWithFirstTransaction(new PaymentModelDao(paymentId, utcNow, utcNow, account.getId(), paymentMethodId, -1, paymentExternalKey), new PaymentTransactionModelDao(transactionId, attempt.getId(), paymentTransactionExternalKey, utcNow, utcNow, paymentId, TransactionType.AUTHORIZE, utcNow, TransactionStatus.PAYMENT_FAILURE, amount, currency, "bla", "foo"), internalCallContext);
processor.retryPaymentTransaction(attempt.getId(), ImmutableList.<String>of(MockPaymentControlProviderPlugin.PLUGIN_NAME), internalCallContext);
final List<PaymentAttemptModelDao> pas = paymentDao.getPaymentAttemptByTransactionExternalKey(paymentTransactionExternalKey, internalCallContext);
assertEquals(pas.size(), 2);
final PaymentAttemptModelDao failedAttempt = Iterables.tryFind(pas, new Predicate<PaymentAttemptModelDao>() {
@Override
public boolean apply(final PaymentAttemptModelDao input) {
return input.getTransactionType() == TransactionType.AUTHORIZE && input.getStateName().equals("ABORTED");
}
}).orNull();
assertNotNull(failedAttempt);
} finally {
if (lock != null) {
lock.release();
}
}
}
Aggregations