Async db writing
This commit is contained in:
parent
5d09e25e87
commit
e115919f1a
2 changed files with 52 additions and 18 deletions
|
|
@ -27,7 +27,6 @@ public class KafkaConfig {
|
||||||
|
|
||||||
@Bean("signalKafkaEventQueue")
|
@Bean("signalKafkaEventQueue")
|
||||||
public BlockingQueue<SignalKafkaEvent> signalKafkaEventQueue(CreditTrackerSettings settings) {
|
public BlockingQueue<SignalKafkaEvent> signalKafkaEventQueue(CreditTrackerSettings settings) {
|
||||||
// TODO add capacity
|
|
||||||
return new LinkedBlockingQueue<>();
|
return new LinkedBlockingQueue<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
import org.springframework.context.annotation.DependsOn;
|
import org.springframework.context.annotation.DependsOn;
|
||||||
import org.springframework.kafka.annotation.KafkaListener;
|
import org.springframework.kafka.annotation.KafkaListener;
|
||||||
import org.springframework.kafka.support.Acknowledgment;
|
import org.springframework.kafka.support.Acknowledgment;
|
||||||
|
import org.springframework.scheduling.concurrent.CustomizableThreadFactory;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings;
|
import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings;
|
||||||
import ru.nbch.credit_tracker.entities.app.Hit;
|
import ru.nbch.credit_tracker.entities.app.Hit;
|
||||||
|
|
@ -23,20 +24,21 @@ import ru.nbch.credit_tracker.service.signal.HitsService;
|
||||||
import ru.nbch.credit_tracker.service.signal.PackageRecordsService;
|
import ru.nbch.credit_tracker.service.signal.PackageRecordsService;
|
||||||
import ru.nbch.credit_tracker.service.signal.SegmentMapService;
|
import ru.nbch.credit_tracker.service.signal.SegmentMapService;
|
||||||
import ru.nbch.credit_tracker.utils.CTUtil;
|
import ru.nbch.credit_tracker.utils.CTUtil;
|
||||||
|
import ru.nbch.credit_tracker.utils.error.ExceptionUtils;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.List;
|
import java.util.concurrent.*;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.BlockingQueue;
|
|
||||||
import java.util.concurrent.Semaphore;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
@DependsOn(value = "signalKafkaEventWriterService")
|
@DependsOn(value = "signalKafkaEventWriterService")
|
||||||
public class KafkaMonitoringService {
|
public class KafkaMonitoringService {
|
||||||
|
|
||||||
|
private final ExecutorService processingExecutor;
|
||||||
|
private final ExecutorService dbExecutor;
|
||||||
|
|
||||||
private volatile boolean isShuttingdDown = false;
|
private volatile boolean isShuttingdDown = false;
|
||||||
private final int permits;
|
private final int permits;
|
||||||
private final Semaphore processingPermits;
|
private final Semaphore processingPermits;
|
||||||
|
|
@ -61,6 +63,15 @@ public class KafkaMonitoringService {
|
||||||
this.permits = Integer.parseInt(settings.getKafkaConsumerSettings().concurency()); // количество равно concurency листенера
|
this.permits = Integer.parseInt(settings.getKafkaConsumerSettings().concurency()); // количество равно concurency листенера
|
||||||
this.hitsService = hitsService;
|
this.hitsService = hitsService;
|
||||||
this.processingPermits = new Semaphore(permits);
|
this.processingPermits = new Semaphore(permits);
|
||||||
|
|
||||||
|
this.processingExecutor = Executors.newFixedThreadPool(
|
||||||
|
permits * 2,
|
||||||
|
new CustomizableThreadFactory("kafka-processor-")
|
||||||
|
);
|
||||||
|
this.dbExecutor = Executors.newFixedThreadPool(
|
||||||
|
permits,
|
||||||
|
new CustomizableThreadFactory("kafka-db-writer-")
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@KafkaListener(
|
@KafkaListener(
|
||||||
|
|
@ -90,8 +101,6 @@ public class KafkaMonitoringService {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void process(List<PackageMessage> messages) {
|
private void process(List<PackageMessage> messages) {
|
||||||
List<Hit> hits = new ArrayList<>();
|
|
||||||
|
|
||||||
Map<Boolean, List<PackageMessage>> partition = messages.stream()
|
Map<Boolean, List<PackageMessage>> partition = messages.stream()
|
||||||
.filter(this::filterMessages)
|
.filter(this::filterMessages)
|
||||||
.collect(Collectors.partitioningBy(m -> m.getPersons() != null && !m.getPersons().isEmpty()));
|
.collect(Collectors.partitioningBy(m -> m.getPersons() != null && !m.getPersons().isEmpty()));
|
||||||
|
|
@ -101,17 +110,43 @@ public class KafkaMonitoringService {
|
||||||
|
|
||||||
Map<String, Integer> segmentMap = segmentMapService.loadSegmentMap();
|
Map<String, Integer> segmentMap = segmentMapService.loadSegmentMap();
|
||||||
|
|
||||||
|
CompletableFuture<List<Hit>> npFuture = CompletableFuture.supplyAsync(() -> {
|
||||||
if (npMessages != null && !npMessages.isEmpty()) {
|
if (npMessages != null && !npMessages.isEmpty()) {
|
||||||
List<Hit> npHits = processNpMessages(npMessages, segmentMap);
|
return processNpMessages(npMessages, segmentMap);
|
||||||
hits.addAll(npHits);
|
|
||||||
}
|
}
|
||||||
|
return Collections.emptyList();
|
||||||
|
}, processingExecutor);
|
||||||
|
|
||||||
|
CompletableFuture<List<Hit>> lpFuture = CompletableFuture.supplyAsync(() -> {
|
||||||
if (lpMessages != null && !lpMessages.isEmpty()) {
|
if (lpMessages != null && !lpMessages.isEmpty()) {
|
||||||
List<Hit> lpHits = processLpMessages(lpMessages, segmentMap);
|
return processLpMessages(lpMessages, segmentMap);
|
||||||
hits.addAll(lpHits);
|
|
||||||
}
|
}
|
||||||
|
return Collections.emptyList();
|
||||||
|
}, processingExecutor);
|
||||||
|
|
||||||
|
CompletableFuture<List<Hit>> combinedFuture = npFuture
|
||||||
|
.thenCombine(lpFuture, (npHits, lpHits) -> {
|
||||||
|
List<Hit> allHits = new ArrayList<>();
|
||||||
|
if (npHits != null) allHits.addAll(npHits);
|
||||||
|
if (lpHits != null) allHits.addAll(lpHits);
|
||||||
|
return allHits;
|
||||||
|
});
|
||||||
|
|
||||||
|
combinedFuture.thenAcceptAsync(hits -> {
|
||||||
|
if (!hits.isEmpty()) {
|
||||||
|
try {
|
||||||
hitsService.insertHits(hits);
|
hitsService.insertHits(hits);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Failed to save hits. {}", ExceptionUtils.getStackTrace(e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, dbExecutor);
|
||||||
|
|
||||||
|
try {
|
||||||
|
combinedFuture.get(1, TimeUnit.MINUTES);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Error processing messages", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Hit> processNpMessages(List<PackageMessage> messages, Map<String, Integer> segmentMap) {
|
private List<Hit> processNpMessages(List<PackageMessage> messages, Map<String, Integer> segmentMap) {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue