Merge branch 'RED-9500' into 'master'
RED-9500: Use Redis pub/sub to syncronize websocket topic messages accross multiple pods Closes RED-9500 See merge request redactmanager/redaction-service!455
This commit is contained in:
commit
71b2dda7cd
@ -0,0 +1,42 @@
|
|||||||
|
package com.iqser.red.service.redaction.v1.server.config;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||||
|
import org.springframework.data.redis.listener.PatternTopic;
|
||||||
|
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
|
||||||
|
import org.springframework.data.redis.listener.adapter.MessageListenerAdapter;
|
||||||
|
import org.springframework.messaging.simp.SimpMessagingTemplate;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.iqser.red.service.redaction.v1.server.service.websocket.RedisPubsubReceiver;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class RedisPubsubConfiguration {
|
||||||
|
|
||||||
|
private final SimpMessagingTemplate template;
|
||||||
|
private final ObjectMapper mapper;
|
||||||
|
private final RedisConnectionFactory connectionFactory;
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public RedisPubsubReceiver redisPubsubReceiver() {
|
||||||
|
return new RedisPubsubReceiver(template, mapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public MessageListenerAdapter redisPubsubListenerAdapter() {
|
||||||
|
return new MessageListenerAdapter(redisPubsubReceiver(), "receiveMessage");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public RedisMessageListenerContainer redisPubsubContainer() {
|
||||||
|
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
|
||||||
|
container.setConnectionFactory(connectionFactory);
|
||||||
|
container.addMessageListener(redisPubsubListenerAdapter(), new PatternTopic("redaction-service-websocket-messages"));
|
||||||
|
return container;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -3,10 +3,9 @@ package com.iqser.red.service.redaction.v1.server.logger;
|
|||||||
import java.time.OffsetDateTime;
|
import java.time.OffsetDateTime;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import com.iqser.red.service.redaction.v1.server.service.WebSocketService;
|
import com.iqser.red.service.redaction.v1.server.service.websocket.WebSocketService;
|
||||||
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.Setter;
|
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class RulesLogger {
|
public class RulesLogger {
|
||||||
|
|||||||
@ -9,8 +9,6 @@ import java.util.concurrent.ExecutionException;
|
|||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.TimeoutException;
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
import org.drools.model.Global;
|
|
||||||
import org.kie.api.definition.KiePackage;
|
|
||||||
import org.kie.api.runtime.KieContainer;
|
import org.kie.api.runtime.KieContainer;
|
||||||
import org.kie.api.runtime.KieSession;
|
import org.kie.api.runtime.KieSession;
|
||||||
import org.kie.api.runtime.rule.QueryResults;
|
import org.kie.api.runtime.rule.QueryResults;
|
||||||
@ -29,7 +27,7 @@ import com.iqser.red.service.redaction.v1.server.logger.RulesLogger;
|
|||||||
import com.iqser.red.service.redaction.v1.server.model.component.Component;
|
import com.iqser.red.service.redaction.v1.server.model.component.Component;
|
||||||
import com.iqser.red.service.redaction.v1.server.model.component.Entity;
|
import com.iqser.red.service.redaction.v1.server.model.component.Entity;
|
||||||
import com.iqser.red.service.redaction.v1.server.model.document.nodes.Document;
|
import com.iqser.red.service.redaction.v1.server.model.document.nodes.Document;
|
||||||
import com.iqser.red.service.redaction.v1.server.service.WebSocketService;
|
import com.iqser.red.service.redaction.v1.server.service.websocket.WebSocketService;
|
||||||
import com.iqser.red.service.redaction.v1.server.service.components.ComponentMappingMemoryCache;
|
import com.iqser.red.service.redaction.v1.server.service.components.ComponentMappingMemoryCache;
|
||||||
import com.iqser.red.service.redaction.v1.server.service.components.ComponentMappingService;
|
import com.iqser.red.service.redaction.v1.server.service.components.ComponentMappingService;
|
||||||
import com.iqser.red.service.redaction.v1.server.service.document.ComponentComparator;
|
import com.iqser.red.service.redaction.v1.server.service.document.ComponentComparator;
|
||||||
|
|||||||
@ -10,8 +10,6 @@ import java.util.concurrent.ExecutionException;
|
|||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.TimeoutException;
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
import org.drools.model.Global;
|
|
||||||
import org.kie.api.KieBase;
|
|
||||||
import org.kie.api.runtime.KieContainer;
|
import org.kie.api.runtime.KieContainer;
|
||||||
import org.kie.api.runtime.KieSession;
|
import org.kie.api.runtime.KieSession;
|
||||||
import org.kie.api.runtime.rule.QueryResults;
|
import org.kie.api.runtime.rule.QueryResults;
|
||||||
@ -30,7 +28,7 @@ import com.iqser.red.service.redaction.v1.server.model.dictionary.Dictionary;
|
|||||||
import com.iqser.red.service.redaction.v1.server.model.document.nodes.Document;
|
import com.iqser.red.service.redaction.v1.server.model.document.nodes.Document;
|
||||||
import com.iqser.red.service.redaction.v1.server.model.document.nodes.SemanticNode;
|
import com.iqser.red.service.redaction.v1.server.model.document.nodes.SemanticNode;
|
||||||
import com.iqser.red.service.redaction.v1.server.service.ManualChangesApplicationService;
|
import com.iqser.red.service.redaction.v1.server.service.ManualChangesApplicationService;
|
||||||
import com.iqser.red.service.redaction.v1.server.service.WebSocketService;
|
import com.iqser.red.service.redaction.v1.server.service.websocket.WebSocketService;
|
||||||
import com.iqser.red.service.redaction.v1.server.service.document.EntityCreationService;
|
import com.iqser.red.service.redaction.v1.server.service.document.EntityCreationService;
|
||||||
import com.iqser.red.service.redaction.v1.server.service.document.EntityEnrichmentService;
|
import com.iqser.red.service.redaction.v1.server.service.document.EntityEnrichmentService;
|
||||||
import com.iqser.red.service.redaction.v1.server.utils.exception.DroolsTimeoutException;
|
import com.iqser.red.service.redaction.v1.server.utils.exception.DroolsTimeoutException;
|
||||||
|
|||||||
@ -0,0 +1,22 @@
|
|||||||
|
package com.iqser.red.service.redaction.v1.server.service.websocket;
|
||||||
|
|
||||||
|
import org.springframework.messaging.simp.SimpMessagingTemplate;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class RedisPubsubReceiver {
|
||||||
|
|
||||||
|
private final SimpMessagingTemplate websocketTemplate;
|
||||||
|
private final ObjectMapper mapper;
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
public void receiveMessage(String message) {
|
||||||
|
var data = mapper.readValue(message, WebSocketMessage.class);
|
||||||
|
websocketTemplate.convertAndSend(data.getTopic(), data.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
package com.iqser.red.service.redaction.v1.server.service.websocket;
|
||||||
|
|
||||||
|
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class RedisSyncedWebSocketService {
|
||||||
|
|
||||||
|
private final StringRedisTemplate redisTemplate;
|
||||||
|
private final ObjectMapper mapper;
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
public void convertAndSend(String topic, Object message) {
|
||||||
|
var socketData = new WebSocketMessage(topic, mapper.writeValueAsString(message));
|
||||||
|
String data = mapper.writeValueAsString(socketData);
|
||||||
|
redisTemplate.convertAndSend("redaction-service-websocket-messages", data);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
package com.iqser.red.service.redaction.v1.server.service.websocket;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class WebSocketMessage {
|
||||||
|
|
||||||
|
private String topic;
|
||||||
|
private String message;
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,6 +1,5 @@
|
|||||||
package com.iqser.red.service.redaction.v1.server.service;
|
package com.iqser.red.service.redaction.v1.server.service.websocket;
|
||||||
|
|
||||||
import org.springframework.messaging.simp.SimpMessagingTemplate;
|
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import com.iqser.red.service.redaction.v1.server.logger.RuleLogEvent;
|
import com.iqser.red.service.redaction.v1.server.logger.RuleLogEvent;
|
||||||
@ -13,7 +12,8 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class WebSocketService {
|
public class WebSocketService {
|
||||||
|
|
||||||
private final SimpMessagingTemplate template;
|
private final RedisSyncedWebSocketService template;
|
||||||
|
|
||||||
|
|
||||||
public void sendLogEvent(RuleLogEvent ruleLogEvent) {
|
public void sendLogEvent(RuleLogEvent ruleLogEvent) {
|
||||||
|
|
||||||
@ -21,4 +21,5 @@ public class WebSocketService {
|
|||||||
log.info("Sending message to url {}", destination);
|
log.info("Sending message to url {}", destination);
|
||||||
template.convertAndSend(destination, ruleLogEvent);
|
template.convertAndSend(destination, ruleLogEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -34,6 +34,7 @@ import org.springframework.boot.test.util.TestPropertyValues;
|
|||||||
import org.springframework.context.ApplicationContextInitializer;
|
import org.springframework.context.ApplicationContextInitializer;
|
||||||
import org.springframework.context.ConfigurableApplicationContext;
|
import org.springframework.context.ConfigurableApplicationContext;
|
||||||
import org.springframework.core.io.ClassPathResource;
|
import org.springframework.core.io.ClassPathResource;
|
||||||
|
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
|
||||||
import org.springframework.test.context.ContextConfiguration;
|
import org.springframework.test.context.ContextConfiguration;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
@ -52,6 +53,7 @@ import com.iqser.red.service.redaction.v1.server.client.RulesClient;
|
|||||||
import com.iqser.red.service.redaction.v1.server.controller.RedactionController;
|
import com.iqser.red.service.redaction.v1.server.controller.RedactionController;
|
||||||
import com.iqser.red.service.redaction.v1.server.service.AnalyzeService;
|
import com.iqser.red.service.redaction.v1.server.service.AnalyzeService;
|
||||||
import com.iqser.red.service.redaction.v1.server.service.UnprocessedChangesService;
|
import com.iqser.red.service.redaction.v1.server.service.UnprocessedChangesService;
|
||||||
|
import com.iqser.red.service.redaction.v1.server.service.websocket.RedisSyncedWebSocketService;
|
||||||
import com.iqser.red.service.redaction.v1.server.storage.RedactionStorageService;
|
import com.iqser.red.service.redaction.v1.server.storage.RedactionStorageService;
|
||||||
import com.iqser.red.service.redaction.v1.server.testcontainers.MongoDBTestContainer;
|
import com.iqser.red.service.redaction.v1.server.testcontainers.MongoDBTestContainer;
|
||||||
import com.iqser.red.service.redaction.v1.server.utils.LayoutParsingRequestProvider;
|
import com.iqser.red.service.redaction.v1.server.utils.LayoutParsingRequestProvider;
|
||||||
@ -167,6 +169,12 @@ public abstract class AbstractRedactionIntegrationTest {
|
|||||||
@MockBean
|
@MockBean
|
||||||
private TenantProvider tenantProvider;
|
private TenantProvider tenantProvider;
|
||||||
|
|
||||||
|
@MockBean
|
||||||
|
private RedisSyncedWebSocketService redisSyncedWebSocketService;
|
||||||
|
|
||||||
|
@MockBean
|
||||||
|
private RedisMessageListenerContainer redisPubsubContainer;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
protected MongoTestConfig mongoTestConfig;
|
protected MongoTestConfig mongoTestConfig;
|
||||||
|
|
||||||
|
|||||||
@ -25,6 +25,7 @@ import org.springframework.context.annotation.Bean;
|
|||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.context.annotation.Import;
|
import org.springframework.context.annotation.Import;
|
||||||
import org.springframework.context.annotation.Primary;
|
import org.springframework.context.annotation.Primary;
|
||||||
|
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
|
||||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||||
|
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
@ -36,6 +37,7 @@ import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemp
|
|||||||
import com.iqser.red.service.redaction.v1.server.client.DictionaryClient;
|
import com.iqser.red.service.redaction.v1.server.client.DictionaryClient;
|
||||||
import com.iqser.red.service.redaction.v1.server.model.dictionary.DictionaryVersion;
|
import com.iqser.red.service.redaction.v1.server.model.dictionary.DictionaryVersion;
|
||||||
import com.iqser.red.service.redaction.v1.server.service.DictionaryService;
|
import com.iqser.red.service.redaction.v1.server.service.DictionaryService;
|
||||||
|
import com.iqser.red.service.redaction.v1.server.service.websocket.RedisSyncedWebSocketService;
|
||||||
import com.iqser.red.storage.commons.service.StorageService;
|
import com.iqser.red.storage.commons.service.StorageService;
|
||||||
import com.iqser.red.storage.commons.utils.FileSystemBackedStorageService;
|
import com.iqser.red.storage.commons.utils.FileSystemBackedStorageService;
|
||||||
import com.knecon.fforesight.keycloakcommons.security.TenantAuthenticationManagerResolver;
|
import com.knecon.fforesight.keycloakcommons.security.TenantAuthenticationManagerResolver;
|
||||||
@ -53,6 +55,12 @@ public class DictionaryServiceTest {
|
|||||||
@MockBean
|
@MockBean
|
||||||
private TenantsClient tenantsClient;
|
private TenantsClient tenantsClient;
|
||||||
|
|
||||||
|
@MockBean
|
||||||
|
private RedisSyncedWebSocketService redisSyncedWebSocketService;
|
||||||
|
|
||||||
|
@MockBean
|
||||||
|
private RedisMessageListenerContainer redisPubsubContainer;
|
||||||
|
|
||||||
@MockBean
|
@MockBean
|
||||||
protected KieContainer kieContainer;
|
protected KieContainer kieContainer;
|
||||||
|
|
||||||
|
|||||||
@ -53,6 +53,7 @@ import org.springframework.context.annotation.FilterType;
|
|||||||
import org.springframework.context.annotation.Import;
|
import org.springframework.context.annotation.Import;
|
||||||
import org.springframework.context.annotation.Primary;
|
import org.springframework.context.annotation.Primary;
|
||||||
import org.springframework.core.io.ClassPathResource;
|
import org.springframework.core.io.ClassPathResource;
|
||||||
|
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
|
||||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||||
@ -81,6 +82,7 @@ import com.iqser.red.service.redaction.v1.server.client.LegalBasisClient;
|
|||||||
import com.iqser.red.service.redaction.v1.server.client.RulesClient;
|
import com.iqser.red.service.redaction.v1.server.client.RulesClient;
|
||||||
import com.iqser.red.service.redaction.v1.server.controller.RedactionController;
|
import com.iqser.red.service.redaction.v1.server.controller.RedactionController;
|
||||||
import com.iqser.red.service.redaction.v1.server.service.AnalyzeService;
|
import com.iqser.red.service.redaction.v1.server.service.AnalyzeService;
|
||||||
|
import com.iqser.red.service.redaction.v1.server.service.websocket.RedisSyncedWebSocketService;
|
||||||
import com.iqser.red.service.redaction.v1.server.storage.RedactionStorageService;
|
import com.iqser.red.service.redaction.v1.server.storage.RedactionStorageService;
|
||||||
import com.iqser.red.service.redaction.v1.server.utils.LayoutParsingRequestProvider;
|
import com.iqser.red.service.redaction.v1.server.utils.LayoutParsingRequestProvider;
|
||||||
import com.iqser.red.service.redaction.v1.server.utils.ResourceLoader;
|
import com.iqser.red.service.redaction.v1.server.utils.ResourceLoader;
|
||||||
@ -257,6 +259,10 @@ public class RulesTest {
|
|||||||
private TenantsClient tenantsClient;
|
private TenantsClient tenantsClient;
|
||||||
@MockBean
|
@MockBean
|
||||||
private TenantAuthenticationManagerResolver tenantAuthenticationManagerResolver;
|
private TenantAuthenticationManagerResolver tenantAuthenticationManagerResolver;
|
||||||
|
@MockBean
|
||||||
|
private RedisSyncedWebSocketService redisSyncedWebSocketService;
|
||||||
|
@MockBean
|
||||||
|
private RedisMessageListenerContainer redisPubsubContainer;
|
||||||
|
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
|
|||||||
@ -21,7 +21,7 @@ import org.mockito.InjectMocks;
|
|||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.junit.jupiter.MockitoExtension;
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
|
|
||||||
import com.iqser.red.service.redaction.v1.server.service.WebSocketService;
|
import com.iqser.red.service.redaction.v1.server.service.websocket.WebSocketService;
|
||||||
|
|
||||||
@ExtendWith(MockitoExtension.class)
|
@ExtendWith(MockitoExtension.class)
|
||||||
class RulesLoggerTest {
|
class RulesLoggerTest {
|
||||||
|
|||||||
@ -34,6 +34,7 @@ import org.springframework.context.annotation.Primary;
|
|||||||
import org.springframework.core.io.ClassPathResource;
|
import org.springframework.core.io.ClassPathResource;
|
||||||
import org.springframework.core.io.Resource;
|
import org.springframework.core.io.Resource;
|
||||||
import org.springframework.core.io.support.ResourcePatternResolver;
|
import org.springframework.core.io.support.ResourcePatternResolver;
|
||||||
|
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
|
||||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.type.TypeReference;
|
import com.fasterxml.jackson.core.type.TypeReference;
|
||||||
@ -52,6 +53,7 @@ import com.iqser.red.service.redaction.v1.server.client.LegalBasisClient;
|
|||||||
import com.iqser.red.service.redaction.v1.server.client.RulesClient;
|
import com.iqser.red.service.redaction.v1.server.client.RulesClient;
|
||||||
import com.iqser.red.service.redaction.v1.server.queue.RedactionMessageReceiver;
|
import com.iqser.red.service.redaction.v1.server.queue.RedactionMessageReceiver;
|
||||||
import com.iqser.red.service.redaction.v1.server.service.DictionaryService;
|
import com.iqser.red.service.redaction.v1.server.service.DictionaryService;
|
||||||
|
import com.iqser.red.service.redaction.v1.server.service.websocket.RedisSyncedWebSocketService;
|
||||||
import com.iqser.red.service.redaction.v1.server.storage.RedactionStorageService;
|
import com.iqser.red.service.redaction.v1.server.storage.RedactionStorageService;
|
||||||
import com.iqser.red.service.redaction.v1.server.utils.ExceptionProvider;
|
import com.iqser.red.service.redaction.v1.server.utils.ExceptionProvider;
|
||||||
import com.iqser.red.storage.commons.StorageAutoConfiguration;
|
import com.iqser.red.storage.commons.StorageAutoConfiguration;
|
||||||
@ -93,6 +95,12 @@ public class LiveDataIntegrationTest {
|
|||||||
@MockBean
|
@MockBean
|
||||||
private LegalBasisClient legalBasisClient;
|
private LegalBasisClient legalBasisClient;
|
||||||
|
|
||||||
|
@MockBean
|
||||||
|
private RedisSyncedWebSocketService redisSyncedWebSocketService;
|
||||||
|
|
||||||
|
@MockBean
|
||||||
|
private RedisMessageListenerContainer redisPubsubContainer;
|
||||||
|
|
||||||
@MockBean
|
@MockBean
|
||||||
protected TenantAuthenticationManagerResolver tenantAuthenticationManagerResolver;
|
protected TenantAuthenticationManagerResolver tenantAuthenticationManagerResolver;
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user