.
This commit is contained in:
parent
0f04ab3e42
commit
a67cc4056a
4 changed files with 156 additions and 46 deletions
|
|
@ -0,0 +1,23 @@
|
||||||
|
package ru.nbch.credit_tracker.service.task;
|
||||||
|
|
||||||
|
import java.util.concurrent.RejectedExecutionException;
|
||||||
|
import java.util.concurrent.RejectedExecutionHandler;
|
||||||
|
import java.util.concurrent.ThreadPoolExecutor;
|
||||||
|
|
||||||
|
public class BlockingRejectedExecutionHandler implements RejectedExecutionHandler {
|
||||||
|
|
||||||
|
public static RejectedExecutionHandler INSTANCE = new BlockingRejectedExecutionHandler();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void rejectedExecution(Runnable r, ThreadPoolExecutor exec) {
|
||||||
|
try {
|
||||||
|
if (exec.isShutdown()) {
|
||||||
|
throw new RejectedExecutionException("Executor is shut down");
|
||||||
|
}
|
||||||
|
exec.getQueue().put(r);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
throw new RejectedExecutionException("Interrupted while enqueueing task", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,12 +1,10 @@
|
||||||
package ru.nbch.credit_tracker.service.task;
|
package ru.nbch.credit_tracker.service.task;
|
||||||
|
|
||||||
import java.util.concurrent.BlockingQueue;
|
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.Semaphore;
|
import java.util.concurrent.Semaphore;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.function.BiFunction;
|
import java.util.function.BiFunction;
|
||||||
import java.util.function.Consumer;
|
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Qualifier;
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
|
|
@ -19,6 +17,7 @@ import ru.nbch.credit_tracker.model.impl.SubjectPayload;
|
||||||
import ru.nbch.credit_tracker.service.signal.SignalRestService;
|
import ru.nbch.credit_tracker.service.signal.SignalRestService;
|
||||||
import ru.nbch.credit_tracker.service.task.impl.FidIdEnricher;
|
import ru.nbch.credit_tracker.service.task.impl.FidIdEnricher;
|
||||||
import ru.nbch.credit_tracker.service.task.impl.FlagsEnricher;
|
import ru.nbch.credit_tracker.service.task.impl.FlagsEnricher;
|
||||||
|
import ru.nbch.credit_tracker.service.task.impl.FlagsEnricherV2;
|
||||||
import ru.nbch.credit_tracker.service.task.impl.SaveSubjectHandler;
|
import ru.nbch.credit_tracker.service.task.impl.SaveSubjectHandler;
|
||||||
import ru.nbch.credit_tracker.service.task.setup.IPipeLineStarter;
|
import ru.nbch.credit_tracker.service.task.setup.IPipeLineStarter;
|
||||||
import ru.nbch.credit_tracker.service.task.setup.IPipeLineTerminator;
|
import ru.nbch.credit_tracker.service.task.setup.IPipeLineTerminator;
|
||||||
|
|
@ -41,6 +40,7 @@ public class PipelinePackageManager {
|
||||||
private final Supplier<IPipeLineTerminator<PartFilePayload, SignalXmlFilePayload>> pipelineTerminatorFactory;
|
private final Supplier<IPipeLineTerminator<PartFilePayload, SignalXmlFilePayload>> pipelineTerminatorFactory;
|
||||||
private final Supplier<FlagsEnricher> flagEnricherFactory;
|
private final Supplier<FlagsEnricher> flagEnricherFactory;
|
||||||
private final BiFunction<Long, String, IPipeLineStarter<SubjectPayload>> pipelineStarterFactory;
|
private final BiFunction<Long, String, IPipeLineStarter<SubjectPayload>> pipelineStarterFactory;
|
||||||
|
private final FlagsEnricherV2 flagsEnricherV2;
|
||||||
private final ExecutorService executorService = Executors.newFixedThreadPool(10, r -> {
|
private final ExecutorService executorService = Executors.newFixedThreadPool(10, r -> {
|
||||||
Thread t = new Thread(r);
|
Thread t = new Thread(r);
|
||||||
t.setName("pipe-starter-%d".formatted(t.threadId()));
|
t.setName("pipe-starter-%d".formatted(t.threadId()));
|
||||||
|
|
@ -60,7 +60,7 @@ public class PipelinePackageManager {
|
||||||
SaveSubjectHandler saveSubjectHandler, FidIdEnricher fidIdEnricherHandler,
|
SaveSubjectHandler saveSubjectHandler, FidIdEnricher fidIdEnricherHandler,
|
||||||
Supplier<IPipeLineTerminator<PartFilePayload, SignalXmlFilePayload>> pipelineTerminatorFactory,
|
Supplier<IPipeLineTerminator<PartFilePayload, SignalXmlFilePayload>> pipelineTerminatorFactory,
|
||||||
Supplier<FlagsEnricher> flagEnricherFactory,
|
Supplier<FlagsEnricher> flagEnricherFactory,
|
||||||
BiFunction<Long, String, IPipeLineStarter<SubjectPayload>> pipelineStarterFactory) {
|
BiFunction<Long, String, IPipeLineStarter<SubjectPayload>> pipelineStarterFactory, FlagsEnricherV2 flagsEnricherV2) {
|
||||||
this.applicationContext = applicationContext;
|
this.applicationContext = applicationContext;
|
||||||
this.xmlProcessor = xmlProcessor;
|
this.xmlProcessor = xmlProcessor;
|
||||||
this.signalRestService = signalRestService;
|
this.signalRestService = signalRestService;
|
||||||
|
|
@ -73,6 +73,7 @@ public class PipelinePackageManager {
|
||||||
this.pipelineTerminatorFactory = pipelineTerminatorFactory;
|
this.pipelineTerminatorFactory = pipelineTerminatorFactory;
|
||||||
this.flagEnricherFactory = flagEnricherFactory;
|
this.flagEnricherFactory = flagEnricherFactory;
|
||||||
this.pipelineStarterFactory = pipelineStarterFactory;
|
this.pipelineStarterFactory = pipelineStarterFactory;
|
||||||
|
this.flagsEnricherV2 = flagsEnricherV2;
|
||||||
this.semaphore = new Semaphore(MAX_PARALLEL_REQUESTS);
|
this.semaphore = new Semaphore(MAX_PARALLEL_REQUESTS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -80,19 +81,12 @@ public class PipelinePackageManager {
|
||||||
if (!semaphore.tryAcquire()) {
|
if (!semaphore.tryAcquire()) {
|
||||||
throw new RuntimeException("Too many concurrent requests");
|
throw new RuntimeException("Too many concurrent requests");
|
||||||
}
|
}
|
||||||
|
log.info("throttler permits after acquire: {}", semaphore.availablePermits());
|
||||||
try {
|
try {
|
||||||
BlockingQueue<SubjectPayload> flagQueue = flagQueueFactory.getObject();
|
|
||||||
Consumer<SubjectPayload> consumer = subjectPayload -> {
|
|
||||||
try {
|
|
||||||
flagQueue.put(subjectPayload);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Pipeline pipeline = PipeLineBuilderV2.first(saveSubjectQueueFactory.getObject(), idEnricherQueueFactory.getObject())
|
Pipeline pipeline = PipeLineBuilderV2.first(saveSubjectQueueFactory.getObject(), idEnricherQueueFactory.getObject())
|
||||||
.handler(saveSubjectHandler)
|
.handler(saveSubjectHandler)
|
||||||
.poison(SubjectPayload.POISON)
|
.poison(SubjectPayload.POISON)
|
||||||
.handlerResult(consumer)
|
.handlerResult(flagsEnricherV2)
|
||||||
.andThen()
|
.andThen()
|
||||||
.stage(sendSignalQueueFactory.getObject())
|
.stage(sendSignalQueueFactory.getObject())
|
||||||
.handler(fidIdEnricherHandler)
|
.handler(fidIdEnricherHandler)
|
||||||
|
|
@ -102,10 +96,6 @@ public class PipelinePackageManager {
|
||||||
.pollFinishingQueue(pipelineTerminatorFactory.get())
|
.pollFinishingQueue(pipelineTerminatorFactory.get())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
FlagsEnricher flagEnricher = flagEnricherFactory.get();
|
|
||||||
flagEnricher.setPollingQueue(flagQueue);
|
|
||||||
|
|
||||||
executorService.submit(flagEnricher);
|
|
||||||
executorService.submit(pipeline.getStarter());
|
executorService.submit(pipeline.getStarter());
|
||||||
executorService.submit(pipeline.getTerminator());
|
executorService.submit(pipeline.getTerminator());
|
||||||
|
|
||||||
|
|
@ -113,42 +103,25 @@ public class PipelinePackageManager {
|
||||||
.doneFuture()
|
.doneFuture()
|
||||||
.orTimeout(5, TimeUnit.MINUTES)
|
.orTimeout(5, TimeUnit.MINUTES)
|
||||||
.whenComplete((v, e) -> {
|
.whenComplete((v, e) -> {
|
||||||
|
try {
|
||||||
if (e != null) {
|
if (e != null) {
|
||||||
log.error(ExceptionUtils.getStackTrace(e));
|
log.error(ExceptionUtils.getStackTrace(e));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
SignalXmlFilePayload res = (SignalXmlFilePayload) v;
|
SignalXmlFilePayload res = (SignalXmlFilePayload) v;
|
||||||
log.trace("Signal file by path: {} is completed", res.getSignalXmlFilePath());
|
log.trace("Signal file by path: {} is completed", res.getSignalXmlFilePath());
|
||||||
try {
|
|
||||||
signalRestService.setupMonitoring(res.getSignalXmlFilePath().toString());
|
signalRestService.setupMonitoring(res.getSignalXmlFilePath().toString());
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
throw new RuntimeException(ex);
|
log.error("pipeline finished with error{}", ExceptionUtils.getStackTrace(ex));
|
||||||
}
|
} finally {
|
||||||
log.info("packageId={}: pipeline finished", packageId);
|
log.info("packageId={}: pipeline finished", packageId);
|
||||||
pipeline.getStages().forEach(Stage::close);
|
pipeline.getStages().forEach(Stage::close);
|
||||||
semaphore.release();
|
semaphore.release();
|
||||||
});
|
|
||||||
|
|
||||||
flagEnricher.doneFuture()
|
|
||||||
.orTimeout(10, TimeUnit.MINUTES)
|
|
||||||
.whenComplete((v, e) -> {
|
|
||||||
if (e != null) {
|
|
||||||
log.error(ExceptionUtils.getStackTrace(e));
|
|
||||||
}
|
}
|
||||||
log.debug("Calculation flags completed");
|
|
||||||
});
|
});
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
semaphore.release();
|
semaphore.release();
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
|
||||||
// try {
|
|
||||||
// pipeline.getLast().doneFuture().get(5, TimeUnit.SECONDS);
|
|
||||||
// log.info("Subjects were registered. PackageId: {}", packageId);
|
|
||||||
// } catch (InterruptedException e) {
|
|
||||||
// Thread.currentThread().interrupt();
|
|
||||||
// return;
|
|
||||||
// } catch (ExecutionException|TimeoutException e) {
|
|
||||||
// log.error(ExceptionUtils.getStackTrace(e));
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,12 +35,13 @@ public class Stage<X extends StagePayload, Z extends StagePayload> implements Ru
|
||||||
this.ioPool = new ThreadPoolExecutor(10,
|
this.ioPool = new ThreadPoolExecutor(10,
|
||||||
10,
|
10,
|
||||||
0L, TimeUnit.MINUTES,
|
0L, TimeUnit.MINUTES,
|
||||||
new LinkedBlockingQueue<>(),
|
new LinkedBlockingQueue<>(1),
|
||||||
r -> {
|
r -> {
|
||||||
Thread t = new Thread(r);
|
Thread t = new Thread(r);
|
||||||
t.setName("pipe-handler-%s-%d".formatted(dispatcher.getClass().getSimpleName(), t.threadId()));
|
t.setName("pipe-handler-%s-%d".formatted(dispatcher.getClass().getSimpleName(), t.threadId()));
|
||||||
return t;
|
return t;
|
||||||
}
|
},
|
||||||
|
BlockingRejectedExecutionHandler.INSTANCE
|
||||||
);
|
);
|
||||||
this.POISON = POISON;
|
this.POISON = POISON;
|
||||||
}
|
}
|
||||||
|
|
@ -152,4 +153,5 @@ public class Stage<X extends StagePayload, Z extends StagePayload> implements Ru
|
||||||
public void setConsumer(Consumer<Z> consumer) {
|
public void setConsumer(Consumer<Z> consumer) {
|
||||||
this.consumer = consumer;
|
this.consumer = consumer;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,112 @@
|
||||||
|
package ru.nbch.credit_tracker.service.task.impl;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
|
import java.util.concurrent.ThreadPoolExecutor;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||||
|
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import ru.nbch.credit_tracker.mapper.signal.PhoneFidMapMapper;
|
||||||
|
import ru.nbch.credit_tracker.model.SubjectProfile;
|
||||||
|
import ru.nbch.credit_tracker.model.impl.SubjectPayload;
|
||||||
|
import ru.nbch.credit_tracker.service.indic.FlagsService2;
|
||||||
|
import ru.nbch.credit_tracker.service.task.BlockingRejectedExecutionHandler;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
public class FlagsEnricherV2 implements Consumer<SubjectPayload> {
|
||||||
|
|
||||||
|
private final FlagsService2 flagsService;
|
||||||
|
private final PhoneFidMapMapper phoneFidMapMapper;
|
||||||
|
private final ExecutorService ioPool;
|
||||||
|
private final ObjectMapper mapper = new ObjectMapper()
|
||||||
|
.registerModule(new JavaTimeModule())
|
||||||
|
.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
|
||||||
|
.setSerializationInclusion(JsonInclude.Include.NON_NULL);
|
||||||
|
|
||||||
|
public FlagsEnricherV2(FlagsService2 flagsService,
|
||||||
|
PhoneFidMapMapper phoneFidMapMapper) {
|
||||||
|
this.flagsService = flagsService;
|
||||||
|
this.phoneFidMapMapper = phoneFidMapMapper;
|
||||||
|
this.ioPool = new ThreadPoolExecutor(10,
|
||||||
|
10,
|
||||||
|
0L, TimeUnit.MINUTES,
|
||||||
|
new LinkedBlockingQueue<>(100),
|
||||||
|
r -> {
|
||||||
|
Thread t = new Thread(r);
|
||||||
|
t.setName("flags-enricher-%d".formatted(t.threadId()));
|
||||||
|
return t;
|
||||||
|
},
|
||||||
|
BlockingRejectedExecutionHandler.INSTANCE
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void process(SubjectPayload subjectPayload) {
|
||||||
|
List<SubjectProfile> subjects = subjectPayload.getSubjects();
|
||||||
|
log.debug("FlagsEnricher handle by packageId: {}, size: {}", subjectPayload.getPackageId(), subjects.size());
|
||||||
|
|
||||||
|
List<Integer> fids = subjects.stream()
|
||||||
|
.map(SubjectProfile::getFid)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.toList();
|
||||||
|
LocalDate yearAgo = LocalDate.now().minusYears(1);
|
||||||
|
|
||||||
|
Map<Integer, Integer> flagsDebt5000 = flagsService.findFlagsDebt5000(fids);
|
||||||
|
Map<Integer, Integer> flag90ByPastDueArrear = flagsService.findFlag90ByPastDueArrear(fids, yearAgo);
|
||||||
|
Map<Integer, Integer> flag90ByRuPaymt = flagsService.findFlag90ByRuPaymt(fids, yearAgo);
|
||||||
|
|
||||||
|
String json;
|
||||||
|
try {
|
||||||
|
json = mapper.writeValueAsString(subjects.stream().map(subject -> {
|
||||||
|
Integer debt5000 = null;
|
||||||
|
Integer flagDays90 = null;
|
||||||
|
LocalDateTime calculatedAt = null;
|
||||||
|
|
||||||
|
if (subject.getFid() != null) {
|
||||||
|
debt5000 = flagsDebt5000.getOrDefault(subject.getFid(), 0);
|
||||||
|
int pastDue90 = flag90ByPastDueArrear.getOrDefault(subject.getFid(), 0);
|
||||||
|
int paymt90 = flag90ByRuPaymt.getOrDefault(subject.getFid(), 0);
|
||||||
|
flagDays90 = Math.max(pastDue90, paymt90);
|
||||||
|
calculatedAt = LocalDateTime.now();
|
||||||
|
}
|
||||||
|
|
||||||
|
Integer finalDebt500 = debt5000;
|
||||||
|
Integer finalFlagDays9 = flagDays90;
|
||||||
|
LocalDateTime finalCalculatedAt = calculatedAt;
|
||||||
|
return new HashMap<String, Object>() {{
|
||||||
|
put("subject_id", subject.getIdentifier());
|
||||||
|
put("fid", subject.getFid());
|
||||||
|
put("phone", subject.getPhone());
|
||||||
|
put("package_id", subjectPayload.getPackageId());
|
||||||
|
put("flag_debt5000", finalDebt500);
|
||||||
|
put("flag_90_12", finalFlagDays9);
|
||||||
|
put("calculated_at", finalCalculatedAt);
|
||||||
|
}};
|
||||||
|
}).toList());
|
||||||
|
} catch (JsonProcessingException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
phoneFidMapMapper.registerJson(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void accept(SubjectPayload subjectPayload) {
|
||||||
|
ThreadPoolExecutor casted = (ThreadPoolExecutor) ioPool;
|
||||||
|
log.info("submitting payload. active tasks number: {}; queue size: {}", casted.getActiveCount(), casted.getQueue().size());
|
||||||
|
this.ioPool.submit(() -> {
|
||||||
|
process(subjectPayload);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue