Merge branch 'RED-9331' into 'master'

RED-9331: Explore possibilities for fair upload / analysis processing per tenant

Closes RED-9331

See merge request redactmanager/redaction-report-service!89
This commit is contained in:
Maverick Studer 2024-08-27 13:23:40 +02:00
commit 10848f43c7
11 changed files with 139 additions and 28 deletions

View File

@ -11,13 +11,13 @@ plugins {
description = "redaction-service-server-v1"
val tenantCommonVersion = "0.23.0"
val tenantCommonVersion = "0.28.0"
val springCommonsVersion = "2.1.0"
val storageCommonsVersion = "2.45.0"
val lifecycleCommonsVersion = "0.4.0"
val poiVersion = "5.2.3"
val metricCommonsVersion = "2.1.0"
val persistenceServiceVersion = "2.522.0"
val persistenceServiceVersion = "2.532.0"
val springBootStarterVersion = "3.2.3"
configurations {

View File

@ -1,5 +1,6 @@
package com.iqser.red.service.redaction.report.v1.server.configuration;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.QueueBuilder;
import org.springframework.context.annotation.Bean;
@ -11,43 +12,39 @@ import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
public class MessagingConfiguration {
public static final String REPORT_QUEUE = "reportQueue";
public static final String REPORT_DLQ = "reportDLQ";
public static final String REPORT_REQUEST_QUEUE_PREFIX = "report_request_queue";
public static final String REPORT_REQUEST_EXCHANGE = "report_request_exchange";
public static final String REPORT_REQUEST_DLQ = "report_request_dlq";
public static final String REPORT_RESULT_QUEUE = "reportResultQueue";
public static final String REPORT_RESULT_DLQ = "reportResultDLQ";
public static final String REPORT_RESPONSE_EXCHANGE = "report_response_exchange";
public static final String REPORT_RESPONSE_DLQ = "report_response_dlq";
@Bean
public Queue reportQueue() {
public DirectExchange reportRequestExchange() {
return QueueBuilder.durable(REPORT_QUEUE)
.withArgument("x-dead-letter-exchange", "")
.withArgument("x-dead-letter-routing-key", REPORT_DLQ)
.withArgument("x-max-priority", 2)
.maxPriority(2)
.build();
return new DirectExchange(REPORT_REQUEST_EXCHANGE);
}
@Bean
public Queue reportDeadLetterQueue() {
public Queue reportRequestDLQ() {
return QueueBuilder.durable(REPORT_DLQ).build();
return QueueBuilder.durable(REPORT_REQUEST_DLQ).build();
}
@Bean
public Queue reportResultQueue() {
public DirectExchange reportResponseExchange() {
return QueueBuilder.durable(REPORT_RESULT_QUEUE).withArgument("x-dead-letter-exchange", "").withArgument("x-dead-letter-routing-key", REPORT_RESULT_DLQ).build();
return new DirectExchange(REPORT_RESPONSE_EXCHANGE);
}
@Bean
public Queue reportResultDeadLetterQueue() {
public Queue reportResponseDLQ() {
return QueueBuilder.durable(REPORT_RESULT_DLQ).build();
return QueueBuilder.durable(REPORT_RESPONSE_DLQ).build();
}
}

View File

@ -0,0 +1,10 @@
package com.iqser.red.service.redaction.report.v1.server.configuration;
import org.springframework.context.annotation.Configuration;
import com.knecon.fforesight.tenantcommons.queue.TenantMessagingConfiguration;
@Configuration
public class TenantMessagingConfigurationImpl extends TenantMessagingConfiguration {
}

View File

@ -1,7 +1,6 @@
package com.iqser.red.service.redaction.report.v1.server.service;
package com.iqser.red.service.redaction.report.v1.server.queue;
import static com.iqser.red.service.redaction.report.v1.server.configuration.MessagingConfiguration.REPORT_QUEUE;
import static com.iqser.red.service.redaction.report.v1.server.configuration.MessagingConfiguration.REPORT_RESULT_QUEUE;
import static com.iqser.red.service.redaction.report.v1.server.configuration.MessagingConfiguration.REPORT_RESPONSE_EXCHANGE;
import org.springframework.amqp.AmqpRejectAndDontRequeueException;
import org.springframework.amqp.core.Message;
@ -13,7 +12,8 @@ import org.springframework.stereotype.Service;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.iqser.red.service.redaction.report.v1.api.model.ReportRequestMessage;
import com.iqser.red.service.redaction.report.v1.api.model.ReportResultMessage;
import com.knecon.fforesight.lifecyclecommons.LifecycleManager;
import com.iqser.red.service.redaction.report.v1.server.service.ReportGenerationService;
import com.knecon.fforesight.tenantcommons.TenantContext;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
@ -24,6 +24,8 @@ import lombok.extern.slf4j.Slf4j;
@RequiredArgsConstructor
public class ReportMessageReceiver {
public static final String REPORT_REQUEST_LISTENER_ID = "report-request-listener";
private final ObjectMapper objectMapper;
private final ReportGenerationService reportGenerationService;
private final RabbitTemplate rabbitTemplate;
@ -31,7 +33,7 @@ public class ReportMessageReceiver {
@SneakyThrows
@RabbitHandler
@RabbitListener(queues = REPORT_QUEUE)
@RabbitListener(id = REPORT_REQUEST_LISTENER_ID)
public void receive(Message message) {
ReportRequestMessage reportMessage = objectMapper.readValue(message.getBody(), ReportRequestMessage.class);
@ -54,7 +56,7 @@ public class ReportMessageReceiver {
private void addToReportResultQueue(String userId, String downloadId, String reportFileInformationStorageId) {
rabbitTemplate.convertAndSend(REPORT_RESULT_QUEUE, new ReportResultMessage(userId, downloadId, reportFileInformationStorageId));
rabbitTemplate.convertAndSend(REPORT_RESPONSE_EXCHANGE, TenantContext.getTenantId(), new ReportResultMessage(userId, downloadId, reportFileInformationStorageId));
}
}

View File

@ -0,0 +1,67 @@
package com.iqser.red.service.redaction.report.v1.server.queue;
import static com.iqser.red.service.redaction.report.v1.server.configuration.MessagingConfiguration.*;
import java.util.Map;
import java.util.Set;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;
import com.knecon.fforesight.tenantcommons.TenantProvider;
import com.knecon.fforesight.tenantcommons.model.TenantCreatedEvent;
import com.knecon.fforesight.tenantcommons.model.TenantQueueConfiguration;
import com.knecon.fforesight.tenantcommons.model.TenantResponse;
import com.knecon.fforesight.tenantcommons.queue.RabbitQueueFromExchangeService;
import com.knecon.fforesight.tenantcommons.queue.TenantExchangeMessageReceiver;
@Service
public class TenantExchangeMessageReceiverImpl extends TenantExchangeMessageReceiver {
public TenantExchangeMessageReceiverImpl(RabbitQueueFromExchangeService rabbitQueueService, TenantProvider tenantProvider) {
super(rabbitQueueService, tenantProvider);
}
@Override
protected Set<TenantQueueConfiguration> getTenantQueueConfigs() {
return Set.of(TenantQueueConfiguration.builder()
.listenerId(ReportMessageReceiver.REPORT_REQUEST_LISTENER_ID)
.exchangeName(REPORT_REQUEST_EXCHANGE)
.queuePrefix(REPORT_REQUEST_QUEUE_PREFIX)
.dlqName(REPORT_REQUEST_DLQ)
.arguments(Map.of("x-max-priority", 2))
.build());
}
@EventListener(ApplicationReadyEvent.class)
public void onApplicationReady() {
System.out.println("application ready invoked");
super.initializeQueues();
}
@RabbitHandler
@RabbitListener(queues = "#{tenantMessagingConfigurationImpl.getTenantCreatedQueueName()}")
public void reactToTenantCreation(TenantCreatedEvent tenantCreatedEvent) {
super.reactToTenantCreation(tenantCreatedEvent);
}
@RabbitHandler
@RabbitListener(queues = "#{tenantMessagingConfigurationImpl.getTenantDeletedQueueName()}")
public void reactToTenantDeletion(TenantResponse tenantResponse) {
super.reactToTenantDeletion(tenantResponse);
}
}

View File

@ -1,6 +1,6 @@
package com.iqser.red.service.redaction.report.v1.server;
import static com.iqser.red.service.redaction.report.v1.server.configuration.MessagingConfiguration.REPORT_RESULT_QUEUE;
import static com.iqser.red.service.redaction.report.v1.server.configuration.MessagingConfiguration.REPORT_RESPONSE_EXCHANGE;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
@ -38,15 +38,16 @@ import com.iqser.red.service.redaction.report.v1.server.client.FileAttributesCon
import com.iqser.red.service.redaction.report.v1.server.client.ReportTemplateClient;
import com.iqser.red.service.redaction.report.v1.server.config.AspectTestConfig;
import com.iqser.red.service.redaction.report.v1.server.configuration.MessagingConfiguration;
import com.iqser.red.service.redaction.report.v1.server.queue.ReportMessageReceiver;
import com.iqser.red.service.redaction.report.v1.server.service.EntityLogConverterService;
import com.iqser.red.service.redaction.report.v1.server.service.ExcelReportGenerationService;
import com.iqser.red.service.redaction.report.v1.server.service.GeneratePlaceholderService;
import com.iqser.red.service.redaction.report.v1.server.service.ReportMessageReceiver;
import com.iqser.red.service.redaction.report.v1.server.service.WordReportGenerationService;
import com.iqser.red.service.redaction.report.v1.server.storage.ReportStorageService;
import com.iqser.red.service.redaction.report.v1.server.utils.TestController;
import com.iqser.red.storage.commons.service.StorageService;
import com.knecon.fforesight.lifecyclecommons.LifecycleManager;
import com.knecon.fforesight.tenantcommons.TenantContext;
import com.knecon.fforesight.tenantcommons.TenantsClient;
import lombok.SneakyThrows;
@ -148,7 +149,7 @@ public class LifecycleAspectTest {
reportMessageReceiver.receive(mockMessage);
lifecycleManager.stop();
verify(rabbitTemplate, times(1)).convertAndSend(eq(REPORT_RESULT_QUEUE), any(ReportResultMessage.class));
verify(rabbitTemplate, times(1)).convertAndSend(eq(REPORT_RESPONSE_EXCHANGE), eq(TenantContext.getTenantId()), any(ReportResultMessage.class));
}
@Test

View File

@ -10,7 +10,9 @@ import org.apache.commons.io.IOUtils;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.listener.RabbitListenerEndpointRegistry;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration;
@ -52,6 +54,12 @@ public class PlaceholderTest {
@MockBean
private RabbitTemplate rabbitTemplate;
@MockBean
protected RabbitAdmin rabbitAdmin;
@MockBean
protected RabbitListenerEndpointRegistry rabbitListenerEndpointRegistry;
@MockBean
private ReportTemplateClient reportTemplateClient;

View File

@ -35,7 +35,9 @@ import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mockito;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.listener.RabbitListenerEndpointRegistry;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration;
@ -99,6 +101,12 @@ public class RedactionReportIntegrationTest {
@MockBean
private RabbitTemplate rabbitTemplate;
@MockBean
protected RabbitAdmin rabbitAdmin;
@MockBean
protected RabbitListenerEndpointRegistry rabbitListenerEndpointRegistry;
@MockBean
private ReportStorageService reportStorageService;

View File

@ -35,7 +35,9 @@ import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.listener.RabbitListenerEndpointRegistry;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration;
@ -75,6 +77,12 @@ public class RedactionReportV2IntegrationTest {
@MockBean
private RabbitTemplate rabbitTemplate;
@MockBean
protected RabbitAdmin rabbitAdmin;
@MockBean
protected RabbitListenerEndpointRegistry rabbitListenerEndpointRegistry;
@MockBean
private ReportTemplateClient reportTemplateClient;

View File

@ -12,6 +12,8 @@ import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.listener.RabbitListenerEndpointRegistry;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
@ -43,6 +45,12 @@ public class EntityLogConverterServiceTest {
private static final String DOSSIER_ID = "DossierId";
private static final String FILE_ID = "FileId";
@MockBean
protected RabbitAdmin rabbitAdmin;
@MockBean
protected RabbitListenerEndpointRegistry rabbitListenerEndpointRegistry;
@MockBean
TenantsClient tenantsClient;

View File

@ -25,3 +25,5 @@ spring:
password: ${MONGODB_PASSWORD}
persistence-service.url: "http://mock.url"
POD_NAME: "redaction-report-service"