mirror of
https://github.com/signalapp/Signal-Server
synced 2026-04-21 23:28:04 +01:00
Migrate from bounded elastic to dedicated executor for message delivery
This commit is contained in:
@@ -60,6 +60,7 @@ import javax.ws.rs.core.Response;
|
||||
import org.glassfish.jersey.server.ServerProperties;
|
||||
import org.glassfish.jersey.test.grizzly.GrizzlyWebTestContainerFactory;
|
||||
import org.hamcrest.Matcher;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -104,6 +105,8 @@ import org.whispersystems.textsecuregcm.util.Pair;
|
||||
import org.whispersystems.textsecuregcm.util.SystemMapper;
|
||||
import org.whispersystems.websocket.Stories;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.core.scheduler.Scheduler;
|
||||
import reactor.core.scheduler.Schedulers;
|
||||
|
||||
@ExtendWith(DropwizardExtensionsSupport.class)
|
||||
class MessageControllerTest {
|
||||
@@ -142,6 +145,7 @@ class MessageControllerTest {
|
||||
private static final PushNotificationManager pushNotificationManager = mock(PushNotificationManager.class);
|
||||
private static final ReportMessageManager reportMessageManager = mock(ReportMessageManager.class);
|
||||
private static final ExecutorService multiRecipientMessageExecutor = mock(ExecutorService.class);
|
||||
private static final Scheduler messageDeliveryScheduler = Schedulers.newBoundedElastic(10, 10_000, "messageDelivery");
|
||||
|
||||
private static final ResourceExtension resources = ResourceExtension.builder()
|
||||
.addProperty(ServerProperties.UNWRAP_COMPLETION_STAGE_IN_WRITER_ENABLE, Boolean.TRUE)
|
||||
@@ -154,7 +158,7 @@ class MessageControllerTest {
|
||||
.addResource(
|
||||
new MessageController(rateLimiters, messageSender, receiptSender, accountsManager, deletedAccountsManager,
|
||||
messagesManager, pushNotificationManager, reportMessageManager, multiRecipientMessageExecutor,
|
||||
ReportSpamTokenProvider.noop()))
|
||||
messageDeliveryScheduler, ReportSpamTokenProvider.noop()))
|
||||
.build();
|
||||
|
||||
@BeforeEach
|
||||
@@ -213,6 +217,11 @@ class MessageControllerTest {
|
||||
);
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
static void teardownAll() {
|
||||
messageDeliveryScheduler.dispose();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSendFromDisabledAccount() throws Exception {
|
||||
Response response =
|
||||
|
||||
@@ -35,6 +35,8 @@ import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicConfigurati
|
||||
import org.whispersystems.textsecuregcm.entities.MessageProtos;
|
||||
import org.whispersystems.textsecuregcm.redis.RedisClusterExtension;
|
||||
import org.whispersystems.textsecuregcm.tests.util.MessagesDynamoDbExtension;
|
||||
import reactor.core.scheduler.Scheduler;
|
||||
import reactor.core.scheduler.Schedulers;
|
||||
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
|
||||
import software.amazon.awssdk.services.dynamodb.model.ScanRequest;
|
||||
|
||||
@@ -47,6 +49,7 @@ class MessagePersisterIntegrationTest {
|
||||
static final RedisClusterExtension REDIS_CLUSTER_EXTENSION = RedisClusterExtension.builder().build();
|
||||
|
||||
private ExecutorService notificationExecutorService;
|
||||
private Scheduler messageDeliveryScheduler;
|
||||
private ExecutorService messageDeletionExecutorService;
|
||||
private MessagesCache messagesCache;
|
||||
private MessagesManager messagesManager;
|
||||
@@ -67,6 +70,7 @@ class MessagePersisterIntegrationTest {
|
||||
|
||||
when(dynamicConfigurationManager.getConfiguration()).thenReturn(new DynamicConfiguration());
|
||||
|
||||
messageDeliveryScheduler = Schedulers.newBoundedElastic(10, 10_000, "messageDelivery");
|
||||
messageDeletionExecutorService = Executors.newSingleThreadExecutor();
|
||||
final MessagesDynamoDb messagesDynamoDb = new MessagesDynamoDb(dynamoDbExtension.getDynamoDbClient(),
|
||||
dynamoDbExtension.getDynamoDbAsyncClient(), MessagesDynamoDbExtension.TABLE_NAME, Duration.ofDays(14),
|
||||
@@ -76,7 +80,7 @@ class MessagePersisterIntegrationTest {
|
||||
notificationExecutorService = Executors.newSingleThreadExecutor();
|
||||
messagesCache = new MessagesCache(REDIS_CLUSTER_EXTENSION.getRedisCluster(),
|
||||
REDIS_CLUSTER_EXTENSION.getRedisCluster(), Clock.systemUTC(), notificationExecutorService,
|
||||
messageDeletionExecutorService);
|
||||
messageDeliveryScheduler, messageDeletionExecutorService);
|
||||
messagesManager = new MessagesManager(messagesDynamoDb, messagesCache, mock(ReportMessageManager.class),
|
||||
messageDeletionExecutorService);
|
||||
messagePersister = new MessagePersister(messagesCache, messagesManager, accountsManager,
|
||||
@@ -102,6 +106,8 @@ class MessagePersisterIntegrationTest {
|
||||
|
||||
messageDeletionExecutorService.shutdown();
|
||||
messageDeletionExecutorService.awaitTermination(15, TimeUnit.SECONDS);
|
||||
|
||||
messageDeliveryScheduler.dispose();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -41,6 +41,8 @@ import org.mockito.stubbing.Answer;
|
||||
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicConfiguration;
|
||||
import org.whispersystems.textsecuregcm.entities.MessageProtos;
|
||||
import org.whispersystems.textsecuregcm.redis.RedisClusterExtension;
|
||||
import reactor.core.scheduler.Scheduler;
|
||||
import reactor.core.scheduler.Schedulers;
|
||||
|
||||
class MessagePersisterTest {
|
||||
|
||||
@@ -48,6 +50,7 @@ class MessagePersisterTest {
|
||||
static final RedisClusterExtension REDIS_CLUSTER_EXTENSION = RedisClusterExtension.builder().build();
|
||||
|
||||
private ExecutorService sharedExecutorService;
|
||||
private Scheduler messageDeliveryScheduler;
|
||||
private MessagesCache messagesCache;
|
||||
private MessagesDynamoDb messagesDynamoDb;
|
||||
private MessagePersister messagePersister;
|
||||
@@ -76,8 +79,10 @@ class MessagePersisterTest {
|
||||
when(dynamicConfigurationManager.getConfiguration()).thenReturn(new DynamicConfiguration());
|
||||
|
||||
sharedExecutorService = Executors.newSingleThreadExecutor();
|
||||
messageDeliveryScheduler = Schedulers.newBoundedElastic(10, 10_000, "messageDelivery");
|
||||
messagesCache = new MessagesCache(REDIS_CLUSTER_EXTENSION.getRedisCluster(),
|
||||
REDIS_CLUSTER_EXTENSION.getRedisCluster(), Clock.systemUTC(), sharedExecutorService, sharedExecutorService);
|
||||
REDIS_CLUSTER_EXTENSION.getRedisCluster(), Clock.systemUTC(), sharedExecutorService, messageDeliveryScheduler,
|
||||
sharedExecutorService);
|
||||
messagePersister = new MessagePersister(messagesCache, messagesManager, accountsManager,
|
||||
dynamicConfigurationManager, PERSIST_DELAY);
|
||||
|
||||
@@ -100,6 +105,8 @@ class MessagePersisterTest {
|
||||
void tearDown() throws Exception {
|
||||
sharedExecutorService.shutdown();
|
||||
sharedExecutorService.awaitTermination(1, TimeUnit.SECONDS);
|
||||
|
||||
messageDeliveryScheduler.dispose();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -64,6 +64,8 @@ import org.whispersystems.textsecuregcm.redis.RedisClusterExtension;
|
||||
import org.whispersystems.textsecuregcm.tests.util.RedisClusterHelper;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.FluxSink;
|
||||
import reactor.core.scheduler.Scheduler;
|
||||
import reactor.core.scheduler.Schedulers;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
class MessagesCacheTest {
|
||||
@@ -78,6 +80,7 @@ class MessagesCacheTest {
|
||||
static final RedisClusterExtension REDIS_CLUSTER_EXTENSION = RedisClusterExtension.builder().build();
|
||||
|
||||
private ExecutorService sharedExecutorService;
|
||||
private Scheduler messageDeliveryScheduler;
|
||||
private MessagesCache messagesCache;
|
||||
|
||||
private static final UUID DESTINATION_UUID = UUID.randomUUID();
|
||||
@@ -92,9 +95,10 @@ class MessagesCacheTest {
|
||||
});
|
||||
|
||||
sharedExecutorService = Executors.newSingleThreadExecutor();
|
||||
messageDeliveryScheduler = Schedulers.newBoundedElastic(10, 10_000, "messageDelivery");
|
||||
messagesCache = new MessagesCache(REDIS_CLUSTER_EXTENSION.getRedisCluster(),
|
||||
REDIS_CLUSTER_EXTENSION.getRedisCluster(), Clock.systemUTC(), sharedExecutorService,
|
||||
sharedExecutorService);
|
||||
messageDeliveryScheduler, sharedExecutorService);
|
||||
|
||||
messagesCache.start();
|
||||
}
|
||||
@@ -105,6 +109,8 @@ class MessagesCacheTest {
|
||||
|
||||
sharedExecutorService.shutdown();
|
||||
sharedExecutorService.awaitTermination(1, TimeUnit.SECONDS);
|
||||
|
||||
messageDeliveryScheduler.dispose();
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@@ -266,6 +272,7 @@ class MessagesCacheTest {
|
||||
REDIS_CLUSTER_EXTENSION.getRedisCluster(),
|
||||
cacheClock,
|
||||
sharedExecutorService,
|
||||
messageDeliveryScheduler,
|
||||
sharedExecutorService);
|
||||
|
||||
final List<MessageProtos.Envelope> actualMessages = Flux.from(
|
||||
@@ -547,6 +554,7 @@ class MessagesCacheTest {
|
||||
private MessagesCache messagesCache;
|
||||
private RedisAdvancedClusterReactiveCommands<byte[], byte[]> reactiveCommands;
|
||||
private RedisAdvancedClusterAsyncCommands<byte[], byte[]> asyncCommands;
|
||||
private Scheduler messageDeliveryScheduler;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@BeforeEach
|
||||
@@ -559,13 +567,16 @@ class MessagesCacheTest {
|
||||
.binaryAsyncCommands(asyncCommands)
|
||||
.build();
|
||||
|
||||
messageDeliveryScheduler = Schedulers.newBoundedElastic(10, 10_000, "messageDelivery");
|
||||
|
||||
messagesCache = new MessagesCache(mockCluster, mockCluster, Clock.systemUTC(), mock(ExecutorService.class),
|
||||
Executors.newSingleThreadExecutor());
|
||||
messageDeliveryScheduler, Executors.newSingleThreadExecutor());
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void teardown() {
|
||||
StepVerifier.resetDefaultTimeout();
|
||||
messageDeliveryScheduler.dispose();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -59,6 +59,7 @@ import org.whispersystems.textsecuregcm.tests.util.MessagesDynamoDbExtension;
|
||||
import org.whispersystems.textsecuregcm.util.Pair;
|
||||
import org.whispersystems.websocket.WebSocketClient;
|
||||
import org.whispersystems.websocket.messages.WebSocketResponseMessage;
|
||||
import reactor.core.scheduler.Scheduler;
|
||||
import reactor.core.scheduler.Schedulers;
|
||||
|
||||
class WebSocketConnectionIntegrationTest {
|
||||
@@ -77,6 +78,7 @@ class WebSocketConnectionIntegrationTest {
|
||||
private Device device;
|
||||
private WebSocketClient webSocketClient;
|
||||
private ScheduledExecutorService retrySchedulingExecutor;
|
||||
private Scheduler messageDeliveryScheduler;
|
||||
|
||||
private long serialTimestamp = System.currentTimeMillis();
|
||||
|
||||
@@ -84,8 +86,10 @@ class WebSocketConnectionIntegrationTest {
|
||||
void setUp() throws Exception {
|
||||
|
||||
sharedExecutorService = Executors.newSingleThreadExecutor();
|
||||
messageDeliveryScheduler = Schedulers.newBoundedElastic(10, 10_000, "messageDelivery");
|
||||
messagesCache = new MessagesCache(REDIS_CLUSTER_EXTENSION.getRedisCluster(),
|
||||
REDIS_CLUSTER_EXTENSION.getRedisCluster(), Clock.systemUTC(), sharedExecutorService, sharedExecutorService);
|
||||
REDIS_CLUSTER_EXTENSION.getRedisCluster(), Clock.systemUTC(), sharedExecutorService, messageDeliveryScheduler,
|
||||
sharedExecutorService);
|
||||
messagesDynamoDb = new MessagesDynamoDb(dynamoDbExtension.getDynamoDbClient(),
|
||||
dynamoDbExtension.getDynamoDbAsyncClient(), MessagesDynamoDbExtension.TABLE_NAME, Duration.ofDays(7),
|
||||
sharedExecutorService);
|
||||
@@ -122,7 +126,8 @@ class WebSocketConnectionIntegrationTest {
|
||||
new AuthenticatedAccount(() -> new Pair<>(account, device)),
|
||||
device,
|
||||
webSocketClient,
|
||||
retrySchedulingExecutor);
|
||||
retrySchedulingExecutor,
|
||||
messageDeliveryScheduler);
|
||||
|
||||
final List<MessageProtos.Envelope> expectedMessages = new ArrayList<>(persistedMessageCount + cachedMessageCount);
|
||||
|
||||
@@ -205,7 +210,8 @@ class WebSocketConnectionIntegrationTest {
|
||||
new AuthenticatedAccount(() -> new Pair<>(account, device)),
|
||||
device,
|
||||
webSocketClient,
|
||||
retrySchedulingExecutor);
|
||||
retrySchedulingExecutor,
|
||||
messageDeliveryScheduler);
|
||||
|
||||
final int persistedMessageCount = 207;
|
||||
final int cachedMessageCount = 173;
|
||||
@@ -271,7 +277,7 @@ class WebSocketConnectionIntegrationTest {
|
||||
webSocketClient,
|
||||
100, // use a very short timeout, so that this test completes quickly
|
||||
retrySchedulingExecutor,
|
||||
Schedulers.boundedElastic());
|
||||
messageDeliveryScheduler);
|
||||
|
||||
final int persistedMessageCount = 207;
|
||||
final int cachedMessageCount = 173;
|
||||
|
||||
@@ -68,6 +68,7 @@ import org.whispersystems.websocket.messages.WebSocketResponseMessage;
|
||||
import org.whispersystems.websocket.session.WebSocketSessionContext;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.FluxSink;
|
||||
import reactor.core.scheduler.Scheduler;
|
||||
import reactor.core.scheduler.Schedulers;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
@@ -90,6 +91,7 @@ class WebSocketConnectionTest {
|
||||
private MessagesManager messagesManager;
|
||||
private ReceiptSender receiptSender;
|
||||
private ScheduledExecutorService retrySchedulingExecutor;
|
||||
private Scheduler messageDeliveryScheduler;
|
||||
|
||||
@BeforeEach
|
||||
void setup() {
|
||||
@@ -102,11 +104,13 @@ class WebSocketConnectionTest {
|
||||
messagesManager = mock(MessagesManager.class);
|
||||
receiptSender = mock(ReceiptSender.class);
|
||||
retrySchedulingExecutor = mock(ScheduledExecutorService.class);
|
||||
messageDeliveryScheduler = Schedulers.newBoundedElastic(10, 10_000, "messageDelivery");
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void teardown() {
|
||||
StepVerifier.resetDefaultTimeout();
|
||||
messageDeliveryScheduler.dispose();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -114,7 +118,7 @@ class WebSocketConnectionTest {
|
||||
WebSocketAccountAuthenticator webSocketAuthenticator = new WebSocketAccountAuthenticator(accountAuthenticator);
|
||||
AuthenticatedConnectListener connectListener = new AuthenticatedConnectListener(receiptSender, messagesManager,
|
||||
mock(PushNotificationManager.class), mock(ClientPresenceManager.class),
|
||||
retrySchedulingExecutor);
|
||||
retrySchedulingExecutor, messageDeliveryScheduler);
|
||||
WebSocketSessionContext sessionContext = mock(WebSocketSessionContext.class);
|
||||
|
||||
when(accountAuthenticator.authenticate(eq(new BasicCredentials(VALID_USER, VALID_PASSWORD))))
|
||||
@@ -773,7 +777,7 @@ class WebSocketConnectionTest {
|
||||
CompletableFuture.completedFuture(Optional.empty()));
|
||||
|
||||
WebSocketConnection connection = new WebSocketConnection(receiptSender, messagesManager, auth, device, client,
|
||||
retrySchedulingExecutor);
|
||||
retrySchedulingExecutor, messageDeliveryScheduler);
|
||||
|
||||
connection.start();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user