FINERACT-2191: ThreadLocal context handling during job execution
This commit is contained in:
committed by
Adam Saghy
parent
0f1d53cbdc
commit
e584e26c39
+3
@@ -23,6 +23,7 @@ import java.time.LocalDate;
|
||||
import java.util.HashMap;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.extern.jackson.Jacksonized;
|
||||
import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
|
||||
@@ -31,6 +32,7 @@ import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
|
||||
@Jacksonized
|
||||
@Builder
|
||||
@Getter
|
||||
@EqualsAndHashCode
|
||||
public class FineractContext implements Serializable {
|
||||
|
||||
private final String contextHolder;
|
||||
@@ -38,4 +40,5 @@ public class FineractContext implements Serializable {
|
||||
private final String authTokenContext;
|
||||
private final HashMap<BusinessDateType, LocalDate> businessDateContext;
|
||||
private final ActionContext actionContext;
|
||||
|
||||
}
|
||||
|
||||
+6
-28
@@ -20,10 +20,16 @@ package org.apache.fineract.infrastructure.core.domain;
|
||||
|
||||
import java.io.Serializable;
|
||||
import lombok.Builder;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.jackson.Jacksonized;
|
||||
|
||||
@Jacksonized
|
||||
@Builder
|
||||
@EqualsAndHashCode
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
public class FineractPlatformTenant implements Serializable {
|
||||
|
||||
private final Long id;
|
||||
@@ -32,32 +38,4 @@ public class FineractPlatformTenant implements Serializable {
|
||||
private final String timezoneId;
|
||||
private final FineractPlatformTenantConnection connection;
|
||||
|
||||
public FineractPlatformTenant(final Long id, final String tenantIdentifier, final String name, final String timezoneId,
|
||||
final FineractPlatformTenantConnection connection) {
|
||||
this.id = id;
|
||||
this.tenantIdentifier = tenantIdentifier;
|
||||
this.name = name;
|
||||
this.timezoneId = timezoneId;
|
||||
this.connection = connection;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public String getTenantIdentifier() {
|
||||
return this.tenantIdentifier;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public String getTimezoneId() {
|
||||
return this.timezoneId;
|
||||
}
|
||||
|
||||
public FineractPlatformTenantConnection getConnection() {
|
||||
return connection;
|
||||
}
|
||||
}
|
||||
|
||||
+3
-1
@@ -27,7 +27,8 @@ import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
*
|
||||
* A utility class for managing ThreadLocal context in the application. Provides methods for context initialization and
|
||||
* cleanup.
|
||||
*/
|
||||
public final class ThreadLocalContextUtil {
|
||||
|
||||
@@ -124,4 +125,5 @@ public final class ThreadLocalContextUtil {
|
||||
businessDateContext.remove();
|
||||
actionContext.remove();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+23
-12
@@ -36,6 +36,7 @@ import org.apache.fineract.infrastructure.event.business.domain.BusinessEvent;
|
||||
import org.apache.fineract.infrastructure.event.business.domain.NoExternalEvent;
|
||||
import org.apache.fineract.infrastructure.event.external.service.ExternalEventService;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.TransactionExecution;
|
||||
import org.springframework.transaction.TransactionExecutionListener;
|
||||
@@ -198,19 +199,29 @@ public class BusinessEventNotifierServiceImpl implements BusinessEventNotifierSe
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeCommit(TransactionExecution transaction) {
|
||||
List<BusinessEventWithContext> businessEventWithContexts = transactionBusinessEvents.get().peek();
|
||||
if (!businessEventWithContexts.isEmpty()) {
|
||||
FineractContext originalContext = ThreadLocalContextUtil.getContext();
|
||||
try {
|
||||
for (BusinessEventWithContext businessEventWithContext : businessEventWithContexts) {
|
||||
ThreadLocalContextUtil.init(businessEventWithContext.getFineractContext());
|
||||
externalEventService.postEvent(businessEventWithContext.getEvent());
|
||||
}
|
||||
} finally {
|
||||
ThreadLocalContextUtil.init(originalContext);
|
||||
}
|
||||
public void beforeCommit(@NonNull final TransactionExecution transaction) {
|
||||
final List<BusinessEventWithContext> businessEventWithContexts = transactionBusinessEvents.get().peek();
|
||||
if (businessEventWithContexts.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
final FineractContext originalContext = ThreadLocalContextUtil.getContext();
|
||||
businessEventWithContexts.forEach(businessEventWithContext -> {
|
||||
final FineractContext currentContext = businessEventWithContext.getFineractContext();
|
||||
boolean swappedContext = false;
|
||||
try {
|
||||
if (!originalContext.equals(currentContext)) {
|
||||
swappedContext = true;
|
||||
ThreadLocalContextUtil.init(currentContext);
|
||||
}
|
||||
externalEventService.postEvent(businessEventWithContext.getEvent());
|
||||
} finally {
|
||||
// Back to original context if we swapped it. We should restore the original context rather than reset
|
||||
// it completely
|
||||
if (swappedContext) {
|
||||
ThreadLocalContextUtil.init(originalContext);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+17
-14
@@ -109,7 +109,7 @@ public class SendAsynchronousEventsTasklet implements Tasklet {
|
||||
eventProducer.sendEvents(partitions);
|
||||
}
|
||||
|
||||
private void markEventsAsSent(List<Long> eventIds) {
|
||||
private void markEventsAsSent(final List<Long> eventIds) {
|
||||
OffsetDateTime sentAt = DateUtils.getAuditOffsetDateTime();
|
||||
|
||||
// Partitioning dataset to avoid exception: PreparedStatement can have at most 65,535 parameters
|
||||
@@ -117,20 +117,23 @@ public class SendAsynchronousEventsTasklet implements Tasklet {
|
||||
List<List<Long>> partitions = Lists.partition(eventIds, partitionSize);
|
||||
List<Future<?>> tasks = new ArrayList<>();
|
||||
final FineractContext context = ThreadLocalContextUtil.getContext();
|
||||
partitions //
|
||||
.forEach(partitionedEventIds -> {
|
||||
tasks.add(threadPoolTaskExecutor.submit(() -> {
|
||||
ThreadLocalContextUtil.init(context);
|
||||
transactionTemplate.execute((status) -> {
|
||||
measure(() -> {
|
||||
repository.markEventsSent(partitionedEventIds, sentAt);
|
||||
}, timeTaken -> {
|
||||
log.debug("Took {}ms to update {} events", timeTaken.toMillis(), partitionedEventIds.size());
|
||||
});
|
||||
return null;
|
||||
partitions.forEach(partitionedEventIds -> {
|
||||
tasks.add(threadPoolTaskExecutor.submit(() -> {
|
||||
try {
|
||||
ThreadLocalContextUtil.init(context);
|
||||
transactionTemplate.execute((status) -> {
|
||||
measure(() -> {
|
||||
repository.markEventsSent(partitionedEventIds, sentAt);
|
||||
}, timeTaken -> {
|
||||
log.debug("Took {}ms to update {} events", timeTaken.toMillis(), partitionedEventIds.size());
|
||||
});
|
||||
}));
|
||||
});
|
||||
return null;
|
||||
});
|
||||
} finally {
|
||||
ThreadLocalContextUtil.reset();
|
||||
}
|
||||
}));
|
||||
});
|
||||
for (Future<?> task : tasks) {
|
||||
try {
|
||||
task.get();
|
||||
|
||||
Reference in New Issue
Block a user