Add machinery to allow a percentage of message sends to succeed.

This commit is contained in:
Jon Chambers 2021-01-15 16:51:03 -05:00 committed by Jon Chambers
parent 4e7ace3b48
commit a57ce1dd17
3 changed files with 98 additions and 61 deletions

View File

@ -380,7 +380,7 @@ public class WhisperServerService extends Application<WhisperServerConfiguration
AttachmentControllerV2 attachmentControllerV2 = new AttachmentControllerV2(rateLimiters, config.getAwsAttachmentsConfiguration().getAccessKey(), config.getAwsAttachmentsConfiguration().getAccessSecret(), config.getAwsAttachmentsConfiguration().getRegion(), config.getAwsAttachmentsConfiguration().getBucket()); AttachmentControllerV2 attachmentControllerV2 = new AttachmentControllerV2(rateLimiters, config.getAwsAttachmentsConfiguration().getAccessKey(), config.getAwsAttachmentsConfiguration().getAccessSecret(), config.getAwsAttachmentsConfiguration().getRegion(), config.getAwsAttachmentsConfiguration().getBucket());
AttachmentControllerV3 attachmentControllerV3 = new AttachmentControllerV3(rateLimiters, config.getGcpAttachmentsConfiguration().getDomain(), config.getGcpAttachmentsConfiguration().getEmail(), config.getGcpAttachmentsConfiguration().getMaxSizeInBytes(), config.getGcpAttachmentsConfiguration().getPathPrefix(), config.getGcpAttachmentsConfiguration().getRsaSigningKey()); AttachmentControllerV3 attachmentControllerV3 = new AttachmentControllerV3(rateLimiters, config.getGcpAttachmentsConfiguration().getDomain(), config.getGcpAttachmentsConfiguration().getEmail(), config.getGcpAttachmentsConfiguration().getMaxSizeInBytes(), config.getGcpAttachmentsConfiguration().getPathPrefix(), config.getGcpAttachmentsConfiguration().getRsaSigningKey());
KeysController keysController = new KeysController(rateLimiters, keys, accountsManager, directoryQueue); KeysController keysController = new KeysController(rateLimiters, keys, accountsManager, directoryQueue);
MessageController messageController = new MessageController(rateLimiters, messageSender, receiptSender, accountsManager, messagesManager, apnFallbackManager); MessageController messageController = new MessageController(rateLimiters, messageSender, receiptSender, accountsManager, messagesManager, apnFallbackManager, featureFlagsManager);
ProfileController profileController = new ProfileController(rateLimiters, accountsManager, profilesManager, usernamesManager, cdnS3Client, profileCdnPolicyGenerator, profileCdnPolicySigner, config.getCdnConfiguration().getBucket(), zkProfileOperations, isZkEnabled); ProfileController profileController = new ProfileController(rateLimiters, accountsManager, profilesManager, usernamesManager, cdnS3Client, profileCdnPolicyGenerator, profileCdnPolicySigner, config.getCdnConfiguration().getBucket(), zkProfileOperations, isZkEnabled);
StickerController stickerController = new StickerController(rateLimiters, config.getCdnConfiguration().getAccessKey(), config.getCdnConfiguration().getAccessSecret(), config.getCdnConfiguration().getRegion(), config.getCdnConfiguration().getBucket()); StickerController stickerController = new StickerController(rateLimiters, config.getCdnConfiguration().getAccessKey(), config.getCdnConfiguration().getAccessSecret(), config.getCdnConfiguration().getRegion(), config.getCdnConfiguration().getBucket());
RemoteConfigController remoteConfigController = new RemoteConfigController(remoteConfigsManager, config.getRemoteConfigConfiguration().getAuthorizedTokens(), config.getRemoteConfigConfiguration().getGlobalConfig()); RemoteConfigController remoteConfigController = new RemoteConfigController(remoteConfigsManager, config.getRemoteConfigConfiguration().getAuthorizedTokens(), config.getRemoteConfigConfiguration().getGlobalConfig());

View File

@ -36,6 +36,7 @@ import org.whispersystems.textsecuregcm.redis.RedisOperation;
import org.whispersystems.textsecuregcm.storage.Account; import org.whispersystems.textsecuregcm.storage.Account;
import org.whispersystems.textsecuregcm.storage.AccountsManager; import org.whispersystems.textsecuregcm.storage.AccountsManager;
import org.whispersystems.textsecuregcm.storage.Device; import org.whispersystems.textsecuregcm.storage.Device;
import org.whispersystems.textsecuregcm.storage.FeatureFlagsManager;
import org.whispersystems.textsecuregcm.storage.MessagesManager; import org.whispersystems.textsecuregcm.storage.MessagesManager;
import org.whispersystems.textsecuregcm.util.Base64; import org.whispersystems.textsecuregcm.util.Base64;
import org.whispersystems.textsecuregcm.util.Constants; import org.whispersystems.textsecuregcm.util.Constants;
@ -61,6 +62,7 @@ import java.util.HashSet;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.Random;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
@ -85,6 +87,9 @@ public class MessageController {
private final MessagesManager messagesManager; private final MessagesManager messagesManager;
private final ApnFallbackManager apnFallbackManager; private final ApnFallbackManager apnFallbackManager;
private final FeatureFlagsManager featureFlagsManager;
private final Random random = new Random();
private static final String CONTENT_SIZE_DISTRIBUTION_NAME = name(MessageController.class, "messageContentSize"); private static final String CONTENT_SIZE_DISTRIBUTION_NAME = name(MessageController.class, "messageContentSize");
private static final String OUTGOING_MESSAGE_LIST_SIZE_BYTES_DISTRIBUTION_NAME = name(MessageController.class, "outgoingMessageListSizeBytes"); private static final String OUTGOING_MESSAGE_LIST_SIZE_BYTES_DISTRIBUTION_NAME = name(MessageController.class, "outgoingMessageListSizeBytes");
@ -95,7 +100,8 @@ public class MessageController {
ReceiptSender receiptSender, ReceiptSender receiptSender,
AccountsManager accountsManager, AccountsManager accountsManager,
MessagesManager messagesManager, MessagesManager messagesManager,
ApnFallbackManager apnFallbackManager) ApnFallbackManager apnFallbackManager,
FeatureFlagsManager featureFlagsManager)
{ {
this.rateLimiters = rateLimiters; this.rateLimiters = rateLimiters;
this.messageSender = messageSender; this.messageSender = messageSender;
@ -103,6 +109,7 @@ public class MessageController {
this.accountsManager = accountsManager; this.accountsManager = accountsManager;
this.messagesManager = messagesManager; this.messagesManager = messagesManager;
this.apnFallbackManager = apnFallbackManager; this.apnFallbackManager = apnFallbackManager;
this.featureFlagsManager = featureFlagsManager;
} }
@Timed @Timed
@ -117,8 +124,8 @@ public class MessageController {
@Valid IncomingMessageList messages) @Valid IncomingMessageList messages)
throws RateLimitExceededException throws RateLimitExceededException
{ {
return Response.status(503).build(); if (random.nextDouble() <= getSuccessPercentage()) {
/* if (!source.isPresent() && !accessKey.isPresent()) { if (!source.isPresent() && !accessKey.isPresent()) {
throw new WebApplicationException(Response.Status.UNAUTHORIZED); throw new WebApplicationException(Response.Status.UNAUTHORIZED);
} }
@ -173,7 +180,7 @@ public class MessageController {
} }
} }
return new SendMessageResponse(!isSyncMessage && source.isPresent() && source.get().getEnabledDeviceCount() > 1); return Response.ok(new SendMessageResponse(!isSyncMessage && source.isPresent() && source.get().getEnabledDeviceCount() > 1)).build();
} catch (NoSuchUserException e) { } catch (NoSuchUserException e) {
throw new WebApplicationException(Response.status(404).build()); throw new WebApplicationException(Response.status(404).build());
} catch (MismatchedDevicesException e) { } catch (MismatchedDevicesException e) {
@ -187,7 +194,35 @@ public class MessageController {
.type(MediaType.APPLICATION_JSON) .type(MediaType.APPLICATION_JSON)
.entity(new StaleDevices(e.getStaleDevices())) .entity(new StaleDevices(e.getStaleDevices()))
.build()); .build());
} */ } } else {
return Response.status(503).build();
}
}
private double getSuccessPercentage() {
if (featureFlagsManager.isFeatureFlagActive("SEND_MESSAGE_1_PERCENT")) {
return 0.01;
} else if (featureFlagsManager.isFeatureFlagActive("SEND_MESSAGE_2_PERCENT")) {
return 0.02;
} else if (featureFlagsManager.isFeatureFlagActive("SEND_MESSAGE_4_PERCENT")) {
return 0.04;
} else if (featureFlagsManager.isFeatureFlagActive("SEND_MESSAGE_8_PERCENT")) {
return 0.08;
} else if (featureFlagsManager.isFeatureFlagActive("SEND_MESSAGE_16_PERCENT")) {
return 0.16;
} else if (featureFlagsManager.isFeatureFlagActive("SEND_MESSAGE_32_PERCENT")) {
return 0.32;
} else if (featureFlagsManager.isFeatureFlagActive("SEND_MESSAGE_48_PERCENT")) {
return 0.48;
} else if (featureFlagsManager.isFeatureFlagActive("SEND_MESSAGE_64_PERCENT")) {
return 0.64;
} else if (featureFlagsManager.isFeatureFlagActive("SEND_MESSAGE_80_PERCENT")) {
return 0.80;
} else if (featureFlagsManager.isFeatureFlagActive("SEND_MESSAGE_100_PERCENT")) {
return 1.0d;
}
return 0;
} }
@Timed @Timed

View File

@ -35,6 +35,7 @@ import org.whispersystems.textsecuregcm.push.ReceiptSender;
import org.whispersystems.textsecuregcm.storage.Account; import org.whispersystems.textsecuregcm.storage.Account;
import org.whispersystems.textsecuregcm.storage.AccountsManager; import org.whispersystems.textsecuregcm.storage.AccountsManager;
import org.whispersystems.textsecuregcm.storage.Device; import org.whispersystems.textsecuregcm.storage.Device;
import org.whispersystems.textsecuregcm.storage.FeatureFlagsManager;
import org.whispersystems.textsecuregcm.storage.MessagesManager; import org.whispersystems.textsecuregcm.storage.MessagesManager;
import org.whispersystems.textsecuregcm.tests.util.AuthHelper; import org.whispersystems.textsecuregcm.tests.util.AuthHelper;
import org.whispersystems.textsecuregcm.util.Base64; import org.whispersystems.textsecuregcm.util.Base64;
@ -86,6 +87,7 @@ public class MessageControllerTest {
private final RateLimiters rateLimiters = mock(RateLimiters.class); private final RateLimiters rateLimiters = mock(RateLimiters.class);
private final RateLimiter rateLimiter = mock(RateLimiter.class); private final RateLimiter rateLimiter = mock(RateLimiter.class);
private final ApnFallbackManager apnFallbackManager = mock(ApnFallbackManager.class); private final ApnFallbackManager apnFallbackManager = mock(ApnFallbackManager.class);
private final FeatureFlagsManager featureFlagsManager = mock(FeatureFlagsManager.class);
private final ObjectMapper mapper = new ObjectMapper(); private final ObjectMapper mapper = new ObjectMapper();
@ -95,7 +97,7 @@ public class MessageControllerTest {
.addProvider(new PolymorphicAuthValueFactoryProvider.Binder<>(ImmutableSet.of(Account.class, DisabledPermittedAccount.class))) .addProvider(new PolymorphicAuthValueFactoryProvider.Binder<>(ImmutableSet.of(Account.class, DisabledPermittedAccount.class)))
.setTestContainerFactory(new GrizzlyWebTestContainerFactory()) .setTestContainerFactory(new GrizzlyWebTestContainerFactory())
.addResource(new MessageController(rateLimiters, messageSender, receiptSender, accountsManager, .addResource(new MessageController(rateLimiters, messageSender, receiptSender, accountsManager,
messagesManager, apnFallbackManager)) messagesManager, apnFallbackManager, featureFlagsManager))
.build(); .build();