http://jira.mfd.msk:8088/browse/CLS-290 Добавил CORRELATION_ID header в сообщения кафки, для использования Spring ReplyingKafkaTemplate

This commit is contained in:
ialbert 2023-05-11 12:18:48 +03:00
parent c8d45cc872
commit 3931d453da
5 changed files with 71 additions and 8 deletions

View file

@ -49,5 +49,9 @@
<artifactId>platform-enum</artifactId> <artifactId>platform-enum</artifactId>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>
</dependency>
</dependencies> </dependencies>
</project> </project>

View file

@ -1,5 +1,6 @@
package ru.spcex.clearing.platform.messaging.domain; package ru.spcex.clearing.platform.messaging.domain;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import ru.spcex.platform.classes.base.interfaces.WithId; import ru.spcex.platform.classes.base.interfaces.WithId;
@ -26,6 +27,9 @@ public class BaseRequest<T> implements WithId {
@JsonProperty @JsonProperty
private Long userId; private Long userId;
@JsonIgnore
private byte[] correlationId;
@Override @Override
public Long getId() { public Long getId() {
return id; return id;
@ -58,4 +62,12 @@ public class BaseRequest<T> implements WithId {
public void setUserId(Long userId) { public void setUserId(Long userId) {
this.userId = userId; this.userId = userId;
} }
public byte[] getCorrelationId() {
return correlationId;
}
public void setCorrelationId(byte[] correlationId) {
this.correlationId = correlationId;
}
} }

View file

@ -9,13 +9,16 @@ import org.apache.kafka.clients.producer.Producer;
import org.apache.kafka.clients.producer.ProducerRecord; import org.apache.kafka.clients.producer.ProducerRecord;
import org.apache.kafka.clients.producer.RecordMetadata; import org.apache.kafka.clients.producer.RecordMetadata;
import org.apache.kafka.common.errors.WakeupException; import org.apache.kafka.common.errors.WakeupException;
import org.apache.kafka.common.header.Header;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.kafka.support.KafkaHeaders;
import ru.spcex.clearing.platform.messaging.domain.ActionType; import ru.spcex.clearing.platform.messaging.domain.ActionType;
import ru.spcex.clearing.platform.messaging.domain.BaseRequest; import ru.spcex.clearing.platform.messaging.domain.BaseRequest;
import ru.spcex.clearing.platform.messaging.domain.Consts; import ru.spcex.clearing.platform.messaging.domain.Consts;
import ru.spcex.clearing.platform.messaging.logic.functional.BuilderConsumerStep; import ru.spcex.clearing.platform.messaging.logic.functional.BuilderConsumerStep;
import ru.spcex.clearing.platform.messaging.logic.functional.ConsumerSpecificClass; import ru.spcex.clearing.platform.messaging.logic.functional.ConsumerSpecificClass;
import ru.spcex.clearing.platform.messaging.service.sender.CorrelationHeader;
import ru.spcex.platform.utils.enumeration.EnumMessage; import ru.spcex.platform.utils.enumeration.EnumMessage;
import ru.spcex.platform.utils.enumeration.IMessageResolver; import ru.spcex.platform.utils.enumeration.IMessageResolver;
import ru.spcex.platform.utils.log.ExceptionUtils; import ru.spcex.platform.utils.log.ExceptionUtils;
@ -80,19 +83,24 @@ public class QueueConsumer implements AutoCloseable {
consumer.subscribe(callbacks.keySet()); consumer.subscribe(callbacks.keySet());
} }
Object o = null; Object o = null;
Header correlationId = null;
int lastErrors = 0; int lastErrors = 0;
while (!closed.get()) { while (!closed.get()) {
try { try {
ConsumerRecords<String, Object> records = consumer.poll(Duration.of(10, ChronoUnit.SECONDS)); ConsumerRecords<String, Object> records = consumer.poll(Duration.of(10, ChronoUnit.SECONDS));
for (ConsumerRecord<String, Object> next : records) { for (ConsumerRecord<String, Object> next : records) {
correlationId = next.headers().lastHeader(KafkaHeaders.CORRELATION_ID);
ConsumerSpecificClass<?> callback = callbacks.get(next.topic()); ConsumerSpecificClass<?> callback = callbacks.get(next.topic());
Class<?> clazz = callback.getClazz(); Class<?> clazz = callback.getClazz();
JavaType payloadType = json.getTypeFactory().constructParametricType(BaseRequest.class, clazz); JavaType payloadType = json.getTypeFactory().constructParametricType(BaseRequest.class, clazz);
o = json.readValue((String) next.value(), payloadType); o = json.readValue((String) next.value(), payloadType);
if (correlationId != null) {
((BaseRequest<?>) o).setCorrelationId(correlationId.value());
}
if (needsProcessing(next.topic(), (BaseRequest<?>) o)) { if (needsProcessing(next.topic(), (BaseRequest<?>) o)) {
Object topicResponse = callback.acceptRaw(o); Object topicResponse = callback.acceptRaw(o);
if (producer != null) { if (producer != null) {
sendResponse((BaseRequest<?>) o, topicResponse); sendResponse((BaseRequest<?>) o, topicResponse, correlationId);
} }
} }
} }
@ -100,7 +108,7 @@ public class QueueConsumer implements AutoCloseable {
} catch (Throwable e) { } catch (Throwable e) {
log.error(ExceptionUtils.getStackTrace(e)); log.error(ExceptionUtils.getStackTrace(e));
if (producer != null && o != null) { if (producer != null && o != null) {
sendErrorResponse((BaseRequest<?>) o); sendErrorResponse((BaseRequest<?>) o, correlationId);
} }
if (lastErrors++ > 20) { if (lastErrors++ > 20) {
log.warn("Too many error at row, {}. Sleep.", lastErrors); log.warn("Too many error at row, {}. Sleep.", lastErrors);
@ -124,7 +132,7 @@ public class QueueConsumer implements AutoCloseable {
} }
//мб перенести в другой класс //мб перенести в другой класс
private void sendErrorResponse(BaseRequest<?> o) { private void sendErrorResponse(BaseRequest<?> o, Header correlationId) {
outputExecutor.submit(() -> { outputExecutor.submit(() -> {
try { try {
Future<RecordMetadata> send; Future<RecordMetadata> send;
@ -136,7 +144,11 @@ public class QueueConsumer implements AutoCloseable {
req.setRequestPayload(success); req.setRequestPayload(success);
req.setId(o.getId()); req.setId(o.getId());
req.setActionType(ActionType.SYSTEM); req.setActionType(ActionType.SYSTEM);
send = producer.send(new ProducerRecord<>(Consts.REQUEST_INFO_UPDATE, req)); ProducerRecord<String, Object> respRec = new ProducerRecord<>(Consts.REQUEST_INFO_UPDATE, req);
if (correlationId != null) {
respRec.headers().add(KafkaHeaders.CORRELATION_ID, correlationId.value());
}
send = producer.send(respRec);
send.get(); send.get();
} catch (Exception e) { } catch (Exception e) {
if (e instanceof InterruptedException) { if (e instanceof InterruptedException) {
@ -147,7 +159,7 @@ public class QueueConsumer implements AutoCloseable {
}); });
} }
private void sendResponse(BaseRequest<?> o, Object response) { private void sendResponse(BaseRequest<?> o, Object response, Header correlationId) {
outputExecutor.submit(() -> { outputExecutor.submit(() -> {
try { try {
Future<RecordMetadata> send; Future<RecordMetadata> send;
@ -163,7 +175,11 @@ public class QueueConsumer implements AutoCloseable {
success.setStatus(Status.Success); success.setStatus(Status.Success);
req.setRequestPayload(success); req.setRequestPayload(success);
} }
send = producer.send(new ProducerRecord<>(Consts.REQUEST_INFO_UPDATE, req)); ProducerRecord<String, Object> respRec = new ProducerRecord<>(Consts.REQUEST_INFO_UPDATE, req);
if (correlationId != null) {
respRec.headers().add(new CorrelationHeader(correlationId.value().clone()));
}
send = producer.send(respRec);
send.get(); send.get();
} catch (Exception e) { } catch (Exception e) {
log.error(ExceptionUtils.getStackTrace(e)); log.error(ExceptionUtils.getStackTrace(e));

View file

@ -0,0 +1,23 @@
package ru.spcex.clearing.platform.messaging.service.sender;
import org.apache.kafka.common.header.Header;
import org.springframework.kafka.support.KafkaHeaders;
public class CorrelationHeader implements Header {
private final byte[] correlationId;
public CorrelationHeader(byte[] correlationId) {
this.correlationId = correlationId;
}
@Override
public String key() {
return KafkaHeaders.CORRELATION_ID;
}
@Override
public byte[] value() {
return correlationId;
}
}

View file

@ -34,14 +34,17 @@ public class KafkaSender {
return new KafkaSenderBuilderImpl(); return new KafkaSenderBuilderImpl();
} }
public Long sendRequestToQueue(String destination, Object requestPayload, byte[] correlationId) {
public Long sendRequestToQueue(String destination, Object requestPayload) {
BaseRequest<Object> request = new BaseRequest<>(); BaseRequest<Object> request = new BaseRequest<>();
request.setId(idGenerator.get()); request.setId(idGenerator.get());
request.setActionType(ActionType.SYSTEM); request.setActionType(ActionType.SYSTEM);
request.setRequestPayload(requestPayload); request.setRequestPayload(requestPayload);
//сохраняет данные о запросе в хранилище //сохраняет данные о запросе в хранилище
saveRequestToStorage(destination, request); saveRequestToStorage(destination, request);
ProducerRecord<Object, BaseRequest<Object>> prdRec = new ProducerRecord<>(destination, request);
if (correlationId != null) {
prdRec.headers().add(new CorrelationHeader(correlationId.clone()));
}
Future<RecordMetadata> send = kafka.send(new ProducerRecord<>(destination, request)); Future<RecordMetadata> send = kafka.send(new ProducerRecord<>(destination, request));
try { try {
send.get(); send.get();
@ -55,6 +58,11 @@ public class KafkaSender {
return request.getId(); return request.getId();
} }
public Long sendRequestToQueue(String destination, Object requestPayload) {
return sendRequestToQueue(destination, requestPayload, null);
}
private void saveRequestToStorage(String destination, BaseRequest<Object> request) { private void saveRequestToStorage(String destination, BaseRequest<Object> request) {
if (!saveRequestInfo) { if (!saveRequestInfo) {
return; return;