handler concurrency & logs
This commit is contained in:
parent
8ce1948b07
commit
28ec19775e
10 changed files with 134 additions and 26 deletions
|
|
@ -0,0 +1,14 @@
|
||||||
|
package ru.nbch.credit_tracker.config.mdc;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
import ru.nbch.credit_tracker.utils.LogUtil;
|
||||||
|
|
||||||
|
// Annotation to only clear the MDC key at method exit
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Target(ElementType.METHOD)
|
||||||
|
public @interface ClearMdc {
|
||||||
|
String key() default LogUtil.mdcKey;
|
||||||
|
}
|
||||||
|
|
@ -1,18 +1,27 @@
|
||||||
package ru.nbch.credit_tracker.config.mdc;
|
package ru.nbch.credit_tracker.config.mdc;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.exception.ExceptionUtils;
|
|
||||||
import org.aspectj.lang.ProceedingJoinPoint;
|
import org.aspectj.lang.ProceedingJoinPoint;
|
||||||
import org.aspectj.lang.annotation.Around;
|
import org.aspectj.lang.annotation.Around;
|
||||||
import org.aspectj.lang.annotation.Aspect;
|
import org.aspectj.lang.annotation.Aspect;
|
||||||
import org.slf4j.MDC;
|
|
||||||
import ru.nbch.credit_tracker.entities.app.UserPackage;
|
import ru.nbch.credit_tracker.entities.app.UserPackage;
|
||||||
import ru.nbch.credit_tracker.entities.user_request.monitoring_request.MonitoringRequest;
|
import ru.nbch.credit_tracker.entities.user_request.monitoring_request.MonitoringRequest;
|
||||||
|
import ru.nbch.credit_tracker.utils.LogUtil;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Aspect
|
@Aspect
|
||||||
public class MdcAspect {
|
public class MdcAspect {
|
||||||
|
|
||||||
|
// For methods that only require clearing the MDC at the end
|
||||||
|
@Around("@annotation(clearMdc)")
|
||||||
|
public Object clearMdcAdvice(ProceedingJoinPoint pjp, ClearMdc clearMdc) throws Throwable {
|
||||||
|
try {
|
||||||
|
return pjp.proceed();
|
||||||
|
} finally {
|
||||||
|
LogUtil.removeMdcLogKey(clearMdc.key());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// For methods that set an MDC value (from a method argument) and then clear it at the end
|
// For methods that set an MDC value (from a method argument) and then clear it at the end
|
||||||
@Around("@annotation(setAndClearMdc)")
|
@Around("@annotation(setAndClearMdc)")
|
||||||
public Object setAndClearMdcAdvice(ProceedingJoinPoint pjp, SetAndClearMdc setAndClearMdc) throws Throwable {
|
public Object setAndClearMdcAdvice(ProceedingJoinPoint pjp, SetAndClearMdc setAndClearMdc) throws Throwable {
|
||||||
|
|
@ -20,30 +29,18 @@ public class MdcAspect {
|
||||||
int index = setAndClearMdc.argIndex();
|
int index = setAndClearMdc.argIndex();
|
||||||
Object obj = (args != null && args.length > index) ? args[index] : null;
|
Object obj = (args != null && args.length > index) ? args[index] : null;
|
||||||
if (obj instanceof MonitoringRequest request) {
|
if (obj instanceof MonitoringRequest request) {
|
||||||
if (request.getPackageName() != null) {
|
LogUtil.addMdcLogKey(setAndClearMdc.key(), request.getPackageName());
|
||||||
putMdcValue(setAndClearMdc.key(), request.getPackageName());
|
|
||||||
}
|
|
||||||
} else if (obj instanceof UserPackage userPackage) {
|
} else if (obj instanceof UserPackage userPackage) {
|
||||||
if (userPackage.getPackageName() != null) {
|
LogUtil.addMdcLogKey(setAndClearMdc.key(), userPackage.getPackageName());
|
||||||
putMdcValue(setAndClearMdc.key(), userPackage.getPackageName());
|
|
||||||
}
|
|
||||||
} else if (obj instanceof String packageName) {
|
} else if (obj instanceof String packageName) {
|
||||||
putMdcValue(setAndClearMdc.key(), packageName);
|
LogUtil.addMdcLogKey(setAndClearMdc.key(), packageName);
|
||||||
} else {
|
} else {
|
||||||
log.debug("no packageName found for for {}", pjp.toShortString());
|
log.debug("no packageName found for for {}", pjp.toShortString());
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
return pjp.proceed();
|
return pjp.proceed();
|
||||||
} finally {
|
} finally {
|
||||||
MDC.remove(setAndClearMdc.key());
|
LogUtil.removeMdcLogKey(setAndClearMdc.key());
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void putMdcValue(String key, String value) {
|
|
||||||
try {
|
|
||||||
MDC.put(key, "[" + value + "] ");
|
|
||||||
} catch (Throwable e) {
|
|
||||||
log.error("{}", ExceptionUtils.getStackTrace(e));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,12 +4,13 @@ import java.lang.annotation.ElementType;
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
import java.lang.annotation.Target;
|
import java.lang.annotation.Target;
|
||||||
|
import ru.nbch.credit_tracker.utils.LogUtil;
|
||||||
|
|
||||||
// Annotation to set an MDC key based on a method argument and clear it after method execution
|
// Annotation to set an MDC key based on a method argument and clear it after method execution
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@Target(ElementType.METHOD)
|
@Target(ElementType.METHOD)
|
||||||
public @interface SetAndClearMdc {
|
public @interface SetAndClearMdc {
|
||||||
String key() default "ru.nbch.credit_tracker.log.mdc.key";
|
String key() default LogUtil.mdcKey;
|
||||||
// The index of the method argument to use for the MDC value (defaults to the first argument)
|
// The index of the method argument to use for the MDC value (defaults to the first argument)
|
||||||
int argIndex() default 0;
|
int argIndex() default 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
import ru.nbch.credit_tracker.config.mdc.ClearMdc;
|
||||||
import ru.nbch.credit_tracker.entities.user_request.active_packages.MonitoringActivePackagesRequest;
|
import ru.nbch.credit_tracker.entities.user_request.active_packages.MonitoringActivePackagesRequest;
|
||||||
import ru.nbch.credit_tracker.entities.user_request.all_packages.MonitoringAllPackagesRequest;
|
import ru.nbch.credit_tracker.entities.user_request.all_packages.MonitoringAllPackagesRequest;
|
||||||
import ru.nbch.credit_tracker.entities.user_response.active_packages.MonitoringActivePackagesResponse;
|
import ru.nbch.credit_tracker.entities.user_response.active_packages.MonitoringActivePackagesResponse;
|
||||||
|
|
@ -34,6 +35,7 @@ public class SignalControllerV3 {
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping(value = "/set", produces = MediaType.APPLICATION_XML_VALUE)
|
@PostMapping(value = "/set", produces = MediaType.APPLICATION_XML_VALUE)
|
||||||
|
@ClearMdc
|
||||||
public ResponseEntity<MonitoringSetupResponse> setupMonitoring(@RequestParam("file") MultipartFile file) {
|
public ResponseEntity<MonitoringSetupResponse> setupMonitoring(@RequestParam("file") MultipartFile file) {
|
||||||
signalFacadeV3.setupMonitoringRequest(file);
|
signalFacadeV3.setupMonitoringRequest(file);
|
||||||
return ResponseEntity.ok().body(new MonitoringSetupResponse());
|
return ResponseEntity.ok().body(new MonitoringSetupResponse());
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@ import ru.nbch.credit_tracker.service.scoring.AuthorizationService;
|
||||||
import ru.nbch.credit_tracker.service.signal.SignalRestService;
|
import ru.nbch.credit_tracker.service.signal.SignalRestService;
|
||||||
import ru.nbch.credit_tracker.service.task.PipelinePackageManager;
|
import ru.nbch.credit_tracker.service.task.PipelinePackageManager;
|
||||||
import ru.nbch.credit_tracker.utils.CTUtil;
|
import ru.nbch.credit_tracker.utils.CTUtil;
|
||||||
|
import ru.nbch.credit_tracker.utils.LogUtil;
|
||||||
import ru.nbch.credit_tracker.utils.ZipUtils;
|
import ru.nbch.credit_tracker.utils.ZipUtils;
|
||||||
import static ru.nbch.credit_tracker.utils.error.ExceptionUtils.clientExcp;
|
import static ru.nbch.credit_tracker.utils.error.ExceptionUtils.clientExcp;
|
||||||
import static ru.nbch.credit_tracker.utils.error.ExceptionUtils.serverExcp;
|
import static ru.nbch.credit_tracker.utils.error.ExceptionUtils.serverExcp;
|
||||||
|
|
@ -114,6 +115,7 @@ public class SignalFacadeV3 {
|
||||||
// }
|
// }
|
||||||
|
|
||||||
Long packageId = signalService.registerPackage(userId, packageName);
|
Long packageId = signalService.registerPackage(userId, packageName);
|
||||||
|
LogUtil.addMdcLogKey("%s %d".formatted(packageName, packageId));
|
||||||
log.info("Package registered. PackageId {}. Status: {}", packageId, Status.PROCESSING.name());
|
log.info("Package registered. PackageId {}. Status: {}", packageId, Status.PROCESSING.name());
|
||||||
pipelinePackageManager.buildAndRun(packageId, filePath);
|
pipelinePackageManager.buildAndRun(packageId, filePath);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
|
|
||||||
|
|
@ -2,4 +2,5 @@ package ru.nbch.credit_tracker.service.task;
|
||||||
|
|
||||||
public interface Handler<X, Z> {
|
public interface Handler<X, Z> {
|
||||||
Z handle(X taskPayload);
|
Z handle(X taskPayload);
|
||||||
|
default int preferredConcurrency() {return 10;}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ 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;
|
||||||
import ru.nbch.credit_tracker.service.task.setup.PipeLineBuilderV2;
|
import ru.nbch.credit_tracker.service.task.setup.PipeLineBuilderV2;
|
||||||
|
import ru.nbch.credit_tracker.utils.LogUtil;
|
||||||
import ru.nbch.credit_tracker.utils.error.ExceptionUtils;
|
import ru.nbch.credit_tracker.utils.error.ExceptionUtils;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
|
|
@ -85,8 +86,8 @@ public class PipelinePackageManager {
|
||||||
.pollFinishingQueue(pipelineTerminatorFactory.get())
|
.pollFinishingQueue(pipelineTerminatorFactory.get())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
executorService.submit(pipeline.getStarter());
|
executorService.submit(LogUtil.wrap(LogUtil.extractMdcMap(), pipeline.getStarter()));
|
||||||
executorService.submit(pipeline.getTerminator());
|
executorService.submit(LogUtil.wrap(LogUtil.extractMdcMap(), pipeline.getTerminator()));
|
||||||
|
|
||||||
pipeline.getTerminator()
|
pipeline.getTerminator()
|
||||||
.doneFuture()
|
.doneFuture()
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ import java.util.function.Consumer;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.exception.ExceptionUtils;
|
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||||
import ru.nbch.credit_tracker.model.StagePayload;
|
import ru.nbch.credit_tracker.model.StagePayload;
|
||||||
|
import ru.nbch.credit_tracker.utils.LogUtil;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class Stage<X extends StagePayload, Z extends StagePayload> implements Runnable {
|
public class Stage<X extends StagePayload, Z extends StagePayload> implements Runnable {
|
||||||
|
|
@ -35,12 +36,13 @@ public class Stage<X extends StagePayload, Z extends StagePayload> implements Ru
|
||||||
this.in = in;
|
this.in = in;
|
||||||
this.out = out;
|
this.out = out;
|
||||||
this.dispatcherName = dispatcher.getClass().getSimpleName();
|
this.dispatcherName = dispatcher.getClass().getSimpleName();
|
||||||
this.ioPool = new ThreadPoolExecutor(10,
|
var mdcMap = LogUtil.extractMdcMap();
|
||||||
10,
|
this.ioPool = new ThreadPoolExecutor(dispatcher.preferredConcurrency(),
|
||||||
|
dispatcher.preferredConcurrency(),
|
||||||
0L, TimeUnit.MINUTES,
|
0L, TimeUnit.MINUTES,
|
||||||
new LinkedBlockingQueue<>(1),
|
new LinkedBlockingQueue<>(1),
|
||||||
r -> {
|
r -> {
|
||||||
Thread t = new Thread(r);
|
Thread t = new Thread(LogUtil.wrap(mdcMap, r));
|
||||||
t.setName("pipe-handler-%s-%d".formatted(dispatcherName, t.threadId()));
|
t.setName("pipe-handler-%s-%d".formatted(dispatcherName, t.threadId()));
|
||||||
return t;
|
return t;
|
||||||
},
|
},
|
||||||
|
|
@ -102,6 +104,9 @@ public class Stage<X extends StagePayload, Z extends StagePayload> implements Ru
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
inflight.add(f);
|
inflight.add(f);
|
||||||
|
if ((counter % 20) == 0) {
|
||||||
|
inflight.removeIf(Future::isDone);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("Error for {}: {}; {}", dispatcherName, info(), ExceptionUtils.getStackTrace(e));
|
log.error("Error for {}: {}; {}", dispatcherName, info(), ExceptionUtils.getStackTrace(e));
|
||||||
|
|
|
||||||
85
src/main/java/ru/nbch/credit_tracker/utils/LogUtil.java
Normal file
85
src/main/java/ru/nbch/credit_tracker/utils/LogUtil.java
Normal file
|
|
@ -0,0 +1,85 @@
|
||||||
|
package ru.nbch.credit_tracker.utils;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.slf4j.MDC;
|
||||||
|
import ru.nbch.credit_tracker.utils.error.ExceptionUtils;
|
||||||
|
|
||||||
|
|
||||||
|
public class LogUtil {
|
||||||
|
private final static Logger log = LoggerFactory.getLogger(LogUtil.class);
|
||||||
|
public static final String mdcKey = "ru.nbch.credit_tracker.log.mdc.key";
|
||||||
|
|
||||||
|
public static void addMdcLogKey(String uuid) {
|
||||||
|
addMdcLogKey(mdcKey, uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void removeMdcLogKey() {
|
||||||
|
removeMdcLogKey(mdcKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void removeMdcLogKey(String key) {
|
||||||
|
try {
|
||||||
|
MDC.remove(key);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
log.error(ExceptionUtils.getStackTrace(e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void addMdcLogKey(String mdcKey, String uuid) {
|
||||||
|
if (uuid != null) {
|
||||||
|
try {
|
||||||
|
MDC.put(mdcKey, "[" + uuid + "] ");
|
||||||
|
} catch (Throwable e) {
|
||||||
|
log.error("{}", ExceptionUtils.getStackTrace(e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Map<String, String> extractMdcMap() {
|
||||||
|
try {
|
||||||
|
return MDC.getCopyOfContextMap();
|
||||||
|
} catch (Throwable e) {
|
||||||
|
log.error(ExceptionUtils.getStackTrace(e));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Runnable wrap(Map<String, String> contextMap, Runnable task) {
|
||||||
|
return () -> {
|
||||||
|
Map<String, String> previous = null;
|
||||||
|
try {
|
||||||
|
try {
|
||||||
|
previous = MDC.getCopyOfContextMap();
|
||||||
|
} catch (Throwable e) {
|
||||||
|
log.error(ExceptionUtils.getStackTrace(e));
|
||||||
|
}
|
||||||
|
// ставим захваченный контекст (может быть null)
|
||||||
|
try {
|
||||||
|
if (contextMap == null) {
|
||||||
|
MDC.clear();
|
||||||
|
} else {
|
||||||
|
MDC.setContextMap(contextMap);
|
||||||
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
log.error(ExceptionUtils.getStackTrace(e));
|
||||||
|
}
|
||||||
|
|
||||||
|
task.run();
|
||||||
|
} finally {
|
||||||
|
// восстанавливаем предыдущий (может быть null)
|
||||||
|
try {
|
||||||
|
if (previous == null) {
|
||||||
|
MDC.clear();
|
||||||
|
} else {
|
||||||
|
MDC.setContextMap(previous);
|
||||||
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
log.error(ExceptionUtils.getStackTrace(e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue