Get rid of MonitoringTimerService
This commit is contained in:
parent
689dd5cf36
commit
d3041a48ba
6 changed files with 30 additions and 201 deletions
|
|
@ -11,7 +11,7 @@ import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory;
|
||||||
import org.springframework.kafka.core.*;
|
import org.springframework.kafka.core.*;
|
||||||
import org.springframework.kafka.listener.ContainerProperties;
|
import org.springframework.kafka.listener.ContainerProperties;
|
||||||
import org.springframework.kafka.support.serializer.JsonDeserializer;
|
import org.springframework.kafka.support.serializer.JsonDeserializer;
|
||||||
import ru.nbch.credit_tracker.service.mode.monitoring.PackageMessage;
|
import ru.nbch.credit_tracker.entities.external_request.kafka.PackageMessage;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
package ru.nbch.credit_tracker.entities.external_request.kafka;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class PackageMessage {
|
||||||
|
private Integer fid;
|
||||||
|
private String memberCode;
|
||||||
|
}
|
||||||
|
|
@ -1,22 +1,12 @@
|
||||||
package ru.nbch.credit_tracker.service.mode.monitoring;
|
package ru.nbch.credit_tracker.service.mode.monitoring;
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
import com.fasterxml.jackson.databind.json.JsonMapper;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.kafka.clients.consumer.ConsumerRecord;
|
|
||||||
import org.springframework.kafka.core.KafkaTemplate;
|
import org.springframework.kafka.core.KafkaTemplate;
|
||||||
import org.springframework.kafka.support.Acknowledgment;
|
import org.springframework.kafka.support.Acknowledgment;
|
||||||
import org.springframework.kafka.support.SendResult;
|
import org.springframework.kafka.support.SendResult;
|
||||||
|
import ru.nbch.credit_tracker.entities.external_request.kafka.PackageMessage;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
import java.nio.file.StandardOpenOption;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Random;
|
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
|
|
@ -24,59 +14,28 @@ import java.util.concurrent.CompletableFuture;
|
||||||
public class KafkaMonitoringService {
|
public class KafkaMonitoringService {
|
||||||
|
|
||||||
private final KafkaTemplate<String, String> kafkaTemplate;
|
private final KafkaTemplate<String, String> kafkaTemplate;
|
||||||
private final MonitoringTimerService monitoringTimerService;
|
|
||||||
|
|
||||||
// @Value("${ct.tmp.dir}")
|
// @Value("${ct.tmp.dir}")
|
||||||
private String tmpDir;
|
private String tmpDir;
|
||||||
|
|
||||||
public KafkaMonitoringService(KafkaTemplate<String, String> kafkaTemplate,
|
public KafkaMonitoringService(KafkaTemplate<String, String> kafkaTemplate) {
|
||||||
MonitoringTimerService monitoringTimerService) {
|
|
||||||
this.kafkaTemplate = kafkaTemplate;
|
this.kafkaTemplate = kafkaTemplate;
|
||||||
this.monitoringTimerService = monitoringTimerService;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// @KafkaListener(
|
// @KafkaListener(
|
||||||
// topics = "my-topic",
|
// topics = "my-topic",
|
||||||
// concurrency = "3"
|
// concurrency = "3"
|
||||||
// )
|
// )
|
||||||
public void listen(List<ConsumerRecord<String, PackageMessage>> records,
|
public void listen(List<PackageMessage> records,
|
||||||
Acknowledgment acknowledgment) {
|
Acknowledgment acknowledgment) {
|
||||||
for (ConsumerRecord<String, PackageMessage> record : records) {
|
process(records);
|
||||||
try {
|
|
||||||
processRecord(record.value());
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("Failed to process record: {}", record, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// insert to db
|
// insert to db
|
||||||
acknowledgment.acknowledge();
|
acknowledgment.acknowledge();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processRecord(PackageMessage msg) throws IOException {
|
private void process(List<PackageMessage> messages) {
|
||||||
Path packageDir = Paths.get(tmpDir, String.valueOf(msg.packageId()));
|
|
||||||
Files.createDirectories(packageDir);
|
|
||||||
|
|
||||||
Path filePath = packageDir.resolve(msg.uuid() + ".xml");
|
|
||||||
Files.writeString(filePath, msg.message(), StandardOpenOption.CREATE_NEW);
|
|
||||||
|
|
||||||
monitoringTimerService.registerFile(msg.packageId(), filePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void generateMessages() throws JsonProcessingException {
|
|
||||||
ObjectMapper mapper = JsonMapper.builder()
|
|
||||||
.build();
|
|
||||||
Random rand = new Random();
|
|
||||||
int max = 10;
|
|
||||||
int min = 1;
|
|
||||||
for (int i = 0; i < 500; i++) {
|
|
||||||
PackageMessage data = new PackageMessage(
|
|
||||||
rand.nextInt((max - min) + 1) + min,
|
|
||||||
"Message " + i,
|
|
||||||
UUID.randomUUID()
|
|
||||||
);
|
|
||||||
|
|
||||||
send(data.uuid().toString(), mapper.writeValueAsString(data));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void send(String id, String data) {
|
private void send(String id, String data) {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,5 @@
|
||||||
package ru.nbch.credit_tracker.service.mode.monitoring;
|
package ru.nbch.credit_tracker.service.mode.monitoring;
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.Setter;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.slf4j.MDC;
|
import org.slf4j.MDC;
|
||||||
|
|
@ -11,6 +9,7 @@ import ru.nbch.credit_tracker.entities.app.Hit;
|
||||||
import ru.nbch.credit_tracker.entities.app.PackagesRecordsMap;
|
import ru.nbch.credit_tracker.entities.app.PackagesRecordsMap;
|
||||||
import ru.nbch.credit_tracker.entities.app.PhonesMap;
|
import ru.nbch.credit_tracker.entities.app.PhonesMap;
|
||||||
import ru.nbch.credit_tracker.entities.app.UserPackage;
|
import ru.nbch.credit_tracker.entities.app.UserPackage;
|
||||||
|
import ru.nbch.credit_tracker.entities.external_request.kafka.PackageMessage;
|
||||||
import ru.nbch.credit_tracker.entities.external_response.online_download.Inquiry;
|
import ru.nbch.credit_tracker.entities.external_response.online_download.Inquiry;
|
||||||
import ru.nbch.credit_tracker.entities.external_response.online_download.Person;
|
import ru.nbch.credit_tracker.entities.external_response.online_download.Person;
|
||||||
import ru.nbch.credit_tracker.entities.external_response.online_download.Persons;
|
import ru.nbch.credit_tracker.entities.external_response.online_download.Persons;
|
||||||
|
|
@ -75,30 +74,15 @@ public class MonitoringService {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void run() {
|
public void run() {
|
||||||
List<MessageData> messages = new ArrayList<>();
|
List<PackageMessage> messages = new ArrayList<>();
|
||||||
|
|
||||||
for (int i = 1000; i < 2000; i++) {
|
for (int i = 1000; i < 2000; i++) {
|
||||||
MessageData messageData = new MessageData();
|
PackageMessage messageData = new PackageMessage();
|
||||||
messageData.setFid(i);
|
messageData.setFid(i);
|
||||||
messageData.setMemberCode("ZX01LL");
|
messageData.setMemberCode("ZX01LL");
|
||||||
messages.add(messageData);
|
messages.add(messageData);
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageData messageData1 = new MessageData();
|
|
||||||
messageData1.setFid(114885613);
|
|
||||||
messageData1.setMemberCode("ZX01LL");
|
|
||||||
messages.add(messageData1);
|
|
||||||
|
|
||||||
MessageData messageData2 = new MessageData();
|
|
||||||
messageData2.setFid(16445000);
|
|
||||||
messageData2.setMemberCode("ZX01LL");
|
|
||||||
messages.add(messageData2);
|
|
||||||
|
|
||||||
MessageData messageData3 = new MessageData();
|
|
||||||
messageData3.setFid(109837221);
|
|
||||||
messageData3.setMemberCode("ZX01LL");
|
|
||||||
messages.add(messageData3);
|
|
||||||
|
|
||||||
|
|
||||||
long start = System.currentTimeMillis();
|
long start = System.currentTimeMillis();
|
||||||
log.info("Start selecting by one");
|
log.info("Start selecting by one");
|
||||||
|
|
@ -111,8 +95,8 @@ public class MonitoringService {
|
||||||
log.info("Finish selecting by bacth. Time: {} ms", System.currentTimeMillis() - start);
|
log.info("Finish selecting by bacth. Time: {} ms", System.currentTimeMillis() - start);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void monitorByOne(List<MessageData> messages) {
|
private void monitorByOne(List<PackageMessage> messages) {
|
||||||
for (MessageData message : messages) {
|
for (PackageMessage message : messages) {
|
||||||
Integer fid = message.getFid();
|
Integer fid = message.getFid();
|
||||||
List<PhonesMap> phonesMaps = packageRecordsService.findCachedByFid(fid);
|
List<PhonesMap> phonesMaps = packageRecordsService.findCachedByFid(fid);
|
||||||
for (PhonesMap phonesMap : phonesMaps) {
|
for (PhonesMap phonesMap : phonesMaps) {
|
||||||
|
|
@ -136,8 +120,8 @@ public class MonitoringService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void monitorbyBatch(List<MessageData> messages) {
|
private void monitorbyBatch(List<PackageMessage> messages) {
|
||||||
List<Integer> fids = messages.stream().map(MessageData::getFid).collect(Collectors.toList());
|
List<Integer> fids = messages.stream().map(PackageMessage::getFid).collect(Collectors.toList());
|
||||||
List<String> memberCodes = messages.stream()
|
List<String> memberCodes = messages.stream()
|
||||||
.map(message -> message.getMemberCode().substring(0,6))
|
.map(message -> message.getMemberCode().substring(0,6))
|
||||||
.toList();
|
.toList();
|
||||||
|
|
@ -161,7 +145,7 @@ public class MonitoringService {
|
||||||
Map<Long, List<UserPackagePhoneData>> userPackagePhoneDataMap = packagePhoneData.stream()
|
Map<Long, List<UserPackagePhoneData>> userPackagePhoneDataMap = packagePhoneData.stream()
|
||||||
.collect(Collectors.groupingBy(UserPackagePhoneData::getPhone));
|
.collect(Collectors.groupingBy(UserPackagePhoneData::getPhone));
|
||||||
|
|
||||||
for (MessageData message : messages) {
|
for (PackageMessage message : messages) {
|
||||||
Integer fid = message.getFid();
|
Integer fid = message.getFid();
|
||||||
String memberCode = message.getMemberCode();
|
String memberCode = message.getMemberCode();
|
||||||
|
|
||||||
|
|
@ -194,14 +178,6 @@ public class MonitoringService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
public static class MessageData {
|
|
||||||
private Integer fid;
|
|
||||||
private String memberCode;
|
|
||||||
// other data
|
|
||||||
}
|
|
||||||
|
|
||||||
private void monitor() {
|
private void monitor() {
|
||||||
try {
|
try {
|
||||||
log.info("Start monitoring");
|
log.info("Start monitoring");
|
||||||
|
|
|
||||||
|
|
@ -1,112 +0,0 @@
|
||||||
package ru.nbch.credit_tracker.service.mode.monitoring;
|
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
|
|
||||||
import java.io.BufferedWriter;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
import java.nio.file.StandardCopyOption;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Queue;
|
|
||||||
import java.util.concurrent.*;
|
|
||||||
|
|
||||||
//@Service
|
|
||||||
@Slf4j
|
|
||||||
public class MonitoringTimerService {
|
|
||||||
|
|
||||||
private static final long DELAY_MINUTES = 5;
|
|
||||||
|
|
||||||
// @Value("${ct.target.dir}")
|
|
||||||
private String targetDir;
|
|
||||||
|
|
||||||
private final ScheduledExecutorService scheduler =
|
|
||||||
Executors.newScheduledThreadPool(4);
|
|
||||||
|
|
||||||
private final ConcurrentHashMap<Integer, PackageBundle> bundles =
|
|
||||||
new ConcurrentHashMap<>();
|
|
||||||
|
|
||||||
public void registerFile(Integer packageId, Path filePath) {
|
|
||||||
bundles.compute(packageId, (id, existing) -> {
|
|
||||||
if (existing == null) {
|
|
||||||
PackageBundle bundle = new PackageBundle();
|
|
||||||
bundle.addFile(filePath);
|
|
||||||
scheduleFlush(packageId, bundle);
|
|
||||||
log.info("Started new timer for packageId={}", packageId);
|
|
||||||
return bundle;
|
|
||||||
}
|
|
||||||
existing.addFile(filePath);
|
|
||||||
return existing;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void scheduleFlush(Integer packageId, PackageBundle bundle) {
|
|
||||||
scheduler.schedule(() -> flush(packageId, bundle), DELAY_MINUTES, TimeUnit.MINUTES);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void flush(Integer packageId, PackageBundle bundle) {
|
|
||||||
// Атомарно забираем snapshot и удаляем из мапы
|
|
||||||
List<Path> snapshot = new ArrayList<>();
|
|
||||||
bundles.compute(packageId, (id, current) -> {
|
|
||||||
snapshot.addAll(bundle.drainFiles());
|
|
||||||
return null; // удаляем этот пакет
|
|
||||||
});
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (!snapshot.isEmpty()) {
|
|
||||||
Path destDir = Paths.get(targetDir, String.valueOf(packageId));
|
|
||||||
Files.createDirectories(destDir);
|
|
||||||
|
|
||||||
List<Path> movedFiles = new ArrayList<>();
|
|
||||||
for (Path src : snapshot) {
|
|
||||||
if (!Files.exists(src)) {
|
|
||||||
log.warn("File missing, skipping: {}", src);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
Path dest = destDir.resolve(src.getFileName());
|
|
||||||
Files.move(src, dest, StandardCopyOption.ATOMIC_MOVE);
|
|
||||||
movedFiles.add(dest);
|
|
||||||
}
|
|
||||||
mergeXmlFiles(movedFiles, destDir, packageId);
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
log.error("Flush failed for packageId={}", packageId, e);
|
|
||||||
} finally {
|
|
||||||
// Файлы, добавленные во время мержа — забираем и стартуем новый цикл
|
|
||||||
bundle.drainFiles().forEach(leftover -> registerFile(packageId, leftover));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void mergeXmlFiles(List<Path> files, Path destDir, Integer packageId) throws IOException {
|
|
||||||
if (files.isEmpty()) return;
|
|
||||||
Path merged = destDir.resolve("merged_" + packageId + ".xml");
|
|
||||||
try (BufferedWriter writer = Files.newBufferedWriter(merged)) {
|
|
||||||
writer.write("<package id=\"" + packageId + "\">");
|
|
||||||
writer.newLine();
|
|
||||||
for (Path file : files) {
|
|
||||||
writer.write(Files.readString(file));
|
|
||||||
writer.newLine();
|
|
||||||
}
|
|
||||||
writer.write("</package>");
|
|
||||||
}
|
|
||||||
log.info("Merged {} files → {} for packageId={}", files.size(), merged, packageId);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private static class PackageBundle {
|
|
||||||
private final Queue<Path> files = new ConcurrentLinkedQueue<>();
|
|
||||||
|
|
||||||
void addFile(Path path) {
|
|
||||||
files.add(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Path> drainFiles() {
|
|
||||||
List<Path> result = new ArrayList<>();
|
|
||||||
Path p;
|
|
||||||
while ((p = files.poll()) != null) result.add(p);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
package ru.nbch.credit_tracker.service.mode.monitoring;
|
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
public record PackageMessage(
|
|
||||||
Integer packageId,
|
|
||||||
String message,
|
|
||||||
UUID uuid
|
|
||||||
) {}
|
|
||||||
Loading…
Add table
Reference in a new issue