Put message persisters behind feature flags.
This commit is contained in:
		
							parent
							
								
									cd4b85b0b5
								
							
						
					
					
						commit
						2b50367d7f
					
				| 
						 | 
					@ -332,8 +332,8 @@ public class WhisperServerService extends Application<WhisperServerConfiguration
 | 
				
			||||||
    TurnTokenGenerator       turnTokenGenerator = new TurnTokenGenerator(config.getTurnConfiguration());
 | 
					    TurnTokenGenerator       turnTokenGenerator = new TurnTokenGenerator(config.getTurnConfiguration());
 | 
				
			||||||
    RecaptchaClient          recaptchaClient    = new RecaptchaClient(config.getRecaptchaConfiguration().getSecret());
 | 
					    RecaptchaClient          recaptchaClient    = new RecaptchaClient(config.getRecaptchaConfiguration().getSecret());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    MessagePersister             messagePersister        = new MessagePersister(messagesClient, messagesManager, pubSubManager, pushSender, accountsManager,config.getMessageCacheConfiguration().getPersistDelayMinutes(), TimeUnit.MINUTES);
 | 
					    MessagePersister             messagePersister        = new MessagePersister(messagesClient, messagesManager, pubSubManager, pushSender, accountsManager, featureFlagsManager, config.getMessageCacheConfiguration().getPersistDelayMinutes(), TimeUnit.MINUTES);
 | 
				
			||||||
    RedisClusterMessagePersister clusterMessagePersister = new RedisClusterMessagePersister(clusterMessagesCache, messages, pubSubManager, pushSender, accountsManager, Duration.ofMinutes(config.getMessageCacheConfiguration().getPersistDelayMinutes()));
 | 
					    RedisClusterMessagePersister clusterMessagePersister = new RedisClusterMessagePersister(clusterMessagesCache, messages, pubSubManager, pushSender, accountsManager, featureFlagsManager, Duration.ofMinutes(config.getMessageCacheConfiguration().getPersistDelayMinutes()));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    DirectoryReconciliationClient directoryReconciliationClient = new DirectoryReconciliationClient(config.getDirectoryConfiguration().getDirectoryServerConfiguration());
 | 
					    DirectoryReconciliationClient directoryReconciliationClient = new DirectoryReconciliationClient(config.getDirectoryConfiguration().getDirectoryServerConfiguration());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -49,30 +49,35 @@ public class MessagePersister implements Managed, Runnable {
 | 
				
			||||||
  private final long                delayTime;
 | 
					  private final long                delayTime;
 | 
				
			||||||
  private final TimeUnit            delayTimeUnit;
 | 
					  private final TimeUnit            delayTimeUnit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private final MessagesManager messagesManager;
 | 
					  private final MessagesManager     messagesManager;
 | 
				
			||||||
  private final PubSubManager   pubSubManager;
 | 
					  private final PubSubManager       pubSubManager;
 | 
				
			||||||
  private final PushSender      pushSender;
 | 
					  private final PushSender          pushSender;
 | 
				
			||||||
  private final AccountsManager accountsManager;
 | 
					  private final AccountsManager     accountsManager;
 | 
				
			||||||
 | 
					  private final FeatureFlagsManager featureFlagsManager;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private final LuaScript getQueuesScript;
 | 
					  private final LuaScript getQueuesScript;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private boolean finished = false;
 | 
					  private boolean finished = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private static final String DISABLE_PERSISTENCE_FLAG = "disable-singleton-persister";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  public MessagePersister(final ReplicatedJedisPool jedisPool,
 | 
					  public MessagePersister(final ReplicatedJedisPool jedisPool,
 | 
				
			||||||
                          final MessagesManager     messagesManager,
 | 
					                          final MessagesManager messagesManager,
 | 
				
			||||||
                          final PubSubManager       pubSubManager,
 | 
					                          final PubSubManager pubSubManager,
 | 
				
			||||||
                          final PushSender          pushSender,
 | 
					                          final PushSender pushSender,
 | 
				
			||||||
                          final AccountsManager     accountsManager,
 | 
					                          final AccountsManager accountsManager,
 | 
				
			||||||
                          final long                delayTime,
 | 
					                          final FeatureFlagsManager featureFlagsManager,
 | 
				
			||||||
                          final TimeUnit            delayTimeUnit)
 | 
					                          final long delayTime,
 | 
				
			||||||
 | 
					                          final TimeUnit delayTimeUnit)
 | 
				
			||||||
      throws IOException
 | 
					      throws IOException
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    this.jedisPool     = jedisPool;
 | 
					    this.jedisPool = jedisPool;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    this.messagesManager = messagesManager;
 | 
					    this.messagesManager     = messagesManager;
 | 
				
			||||||
    this.pubSubManager   = pubSubManager;
 | 
					    this.pubSubManager       = pubSubManager;
 | 
				
			||||||
    this.pushSender      = pushSender;
 | 
					    this.pushSender          = pushSender;
 | 
				
			||||||
    this.accountsManager = accountsManager;
 | 
					    this.accountsManager     = accountsManager;
 | 
				
			||||||
 | 
					    this.featureFlagsManager = featureFlagsManager;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    this.delayTime       = delayTime;
 | 
					    this.delayTime       = delayTime;
 | 
				
			||||||
    this.delayTimeUnit   = delayTimeUnit;
 | 
					    this.delayTimeUnit   = delayTimeUnit;
 | 
				
			||||||
| 
						 | 
					@ -87,23 +92,30 @@ public class MessagePersister implements Managed, Runnable {
 | 
				
			||||||
  @Override
 | 
					  @Override
 | 
				
			||||||
  public void run() {
 | 
					  public void run() {
 | 
				
			||||||
    while (running.get()) {
 | 
					    while (running.get()) {
 | 
				
			||||||
      try {
 | 
					      if (!featureFlagsManager.isFeatureFlagActive(DISABLE_PERSISTENCE_FLAG)) {
 | 
				
			||||||
        List<byte[]> queuesToPersist = getQueuesToPersist();
 | 
					        try {
 | 
				
			||||||
        queueCountHistogram.update(queuesToPersist.size());
 | 
					          List<byte[]> queuesToPersist = getQueuesToPersist();
 | 
				
			||||||
 | 
					          queueCountHistogram.update(queuesToPersist.size());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for (byte[] queue : queuesToPersist) {
 | 
					          for (byte[] queue : queuesToPersist) {
 | 
				
			||||||
          Key key = Key.fromUserMessageQueue(queue);
 | 
					            Key key = Key.fromUserMessageQueue(queue);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          persistQueue(jedisPool, key);
 | 
					            persistQueue(jedisPool, key);
 | 
				
			||||||
          notifyClients(accountsManager, pubSubManager, pushSender, key);
 | 
					            notifyClients(accountsManager, pubSubManager, pushSender, key);
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          if (queuesToPersist.isEmpty()) {
 | 
				
			||||||
 | 
					            //noinspection BusyWait
 | 
				
			||||||
 | 
					            Thread.sleep(10_000);
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        } catch (Throwable t) {
 | 
				
			||||||
 | 
					          logger.error("Exception while persisting: ", t);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
        if (queuesToPersist.isEmpty()) {
 | 
					        try {
 | 
				
			||||||
          //noinspection BusyWait
 | 
					 | 
				
			||||||
          Thread.sleep(10_000);
 | 
					          Thread.sleep(10_000);
 | 
				
			||||||
 | 
					        } catch (final InterruptedException ignored) {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      } catch (Throwable t) {
 | 
					 | 
				
			||||||
        logger.error("Exception while persisting: ", t);
 | 
					 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -30,6 +30,7 @@ public class RedisClusterMessagePersister implements Managed {
 | 
				
			||||||
    private final PubSubManager             pubSubManager;
 | 
					    private final PubSubManager             pubSubManager;
 | 
				
			||||||
    private final PushSender                pushSender;
 | 
					    private final PushSender                pushSender;
 | 
				
			||||||
    private final AccountsManager           accountsManager;
 | 
					    private final AccountsManager           accountsManager;
 | 
				
			||||||
 | 
					    private final FeatureFlagsManager       featureFlagsManager;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private final Duration persistDelay;
 | 
					    private final Duration persistDelay;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -46,16 +47,18 @@ public class RedisClusterMessagePersister implements Managed {
 | 
				
			||||||
    static final int QUEUE_BATCH_LIMIT   = 100;
 | 
					    static final int QUEUE_BATCH_LIMIT   = 100;
 | 
				
			||||||
    static final int MESSAGE_BATCH_LIMIT = 100;
 | 
					    static final int MESSAGE_BATCH_LIMIT = 100;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    static final String ENABLE_PERSISTENCE_FLAG = "enable-cluster-persister";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private static final Logger logger = LoggerFactory.getLogger(RedisClusterMessagePersister.class);
 | 
					    private static final Logger logger = LoggerFactory.getLogger(RedisClusterMessagePersister.class);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public RedisClusterMessagePersister(final RedisClusterMessagesCache messagesCache, final Messages messagesDatabase, final PubSubManager pubSubManager, final PushSender pushSender, final AccountsManager accountsManager, final Duration persistDelay) {
 | 
					    public RedisClusterMessagePersister(final RedisClusterMessagesCache messagesCache, final Messages messagesDatabase, final PubSubManager pubSubManager, final PushSender pushSender, final AccountsManager accountsManager, final FeatureFlagsManager featureFlagsManager, final Duration persistDelay) {
 | 
				
			||||||
        this.messagesCache    = messagesCache;
 | 
					        this.messagesCache       = messagesCache;
 | 
				
			||||||
        this.messagesDatabase = messagesDatabase;
 | 
					        this.messagesDatabase    = messagesDatabase;
 | 
				
			||||||
        this.pubSubManager    = pubSubManager;
 | 
					        this.pubSubManager       = pubSubManager;
 | 
				
			||||||
        this.pushSender       = pushSender;
 | 
					        this.pushSender          = pushSender;
 | 
				
			||||||
        this.accountsManager  = accountsManager;
 | 
					        this.accountsManager     = accountsManager;
 | 
				
			||||||
 | 
					        this.featureFlagsManager = featureFlagsManager;
 | 
				
			||||||
        this.persistDelay     = persistDelay;
 | 
					        this.persistDelay        = persistDelay;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @VisibleForTesting
 | 
					    @VisibleForTesting
 | 
				
			||||||
| 
						 | 
					@ -69,7 +72,10 @@ public class RedisClusterMessagePersister implements Managed {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        workerThread = new Thread(() -> {
 | 
					        workerThread = new Thread(() -> {
 | 
				
			||||||
            while (running) {
 | 
					            while (running) {
 | 
				
			||||||
                persistNextQueues(Instant.now());
 | 
					                if (featureFlagsManager.isFeatureFlagActive(ENABLE_PERSISTENCE_FLAG)) {
 | 
				
			||||||
 | 
					                    persistNextQueues(Instant.now());
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Util.sleep(100);
 | 
					                Util.sleep(100);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
| 
						 | 
					@ -130,7 +136,7 @@ public class RedisClusterMessagePersister implements Managed {
 | 
				
			||||||
            messagesCache.lockQueueForPersistence(queue);
 | 
					            messagesCache.lockQueueForPersistence(queue);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            try {
 | 
					            try {
 | 
				
			||||||
                /* int messageCount = 0;
 | 
					                int messageCount = 0;
 | 
				
			||||||
                List<MessageProtos.Envelope> messages;
 | 
					                List<MessageProtos.Envelope> messages;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                do {
 | 
					                do {
 | 
				
			||||||
| 
						 | 
					@ -146,7 +152,7 @@ public class RedisClusterMessagePersister implements Managed {
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                } while (!messages.isEmpty());
 | 
					                } while (!messages.isEmpty());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                queueSizeHistogram.update(messageCount); */
 | 
					                queueSizeHistogram.update(messageCount);
 | 
				
			||||||
            } finally {
 | 
					            } finally {
 | 
				
			||||||
                messagesCache.unlockQueueForPersistence(queue);
 | 
					                messagesCache.unlockQueueForPersistence(queue);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,7 +4,6 @@ import com.google.protobuf.ByteString;
 | 
				
			||||||
import io.lettuce.core.cluster.SlotHash;
 | 
					import io.lettuce.core.cluster.SlotHash;
 | 
				
			||||||
import org.apache.commons.lang3.RandomStringUtils;
 | 
					import org.apache.commons.lang3.RandomStringUtils;
 | 
				
			||||||
import org.junit.Before;
 | 
					import org.junit.Before;
 | 
				
			||||||
import org.junit.Ignore;
 | 
					 | 
				
			||||||
import org.junit.Test;
 | 
					import org.junit.Test;
 | 
				
			||||||
import org.whispersystems.textsecuregcm.entities.MessageProtos;
 | 
					import org.whispersystems.textsecuregcm.entities.MessageProtos;
 | 
				
			||||||
import org.whispersystems.textsecuregcm.push.PushSender;
 | 
					import org.whispersystems.textsecuregcm.push.PushSender;
 | 
				
			||||||
| 
						 | 
					@ -29,7 +28,6 @@ import static org.mockito.Mockito.times;
 | 
				
			||||||
import static org.mockito.Mockito.verify;
 | 
					import static org.mockito.Mockito.verify;
 | 
				
			||||||
import static org.mockito.Mockito.when;
 | 
					import static org.mockito.Mockito.when;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Ignore
 | 
					 | 
				
			||||||
public class RedisClusterMessagePersisterTest extends AbstractRedisClusterTest {
 | 
					public class RedisClusterMessagePersisterTest extends AbstractRedisClusterTest {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private ExecutorService              notificationExecutorService;
 | 
					    private ExecutorService              notificationExecutorService;
 | 
				
			||||||
| 
						 | 
					@ -50,6 +48,9 @@ public class RedisClusterMessagePersisterTest extends AbstractRedisClusterTest {
 | 
				
			||||||
    public void setUp() throws Exception {
 | 
					    public void setUp() throws Exception {
 | 
				
			||||||
        super.setUp();
 | 
					        super.setUp();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        final FeatureFlagsManager featureFlagsManager = mock(FeatureFlagsManager.class);
 | 
				
			||||||
 | 
					        when(featureFlagsManager.isFeatureFlagActive(RedisClusterMessagePersister.ENABLE_PERSISTENCE_FLAG)).thenReturn(true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        messagesDatabase = mock(Messages.class);
 | 
					        messagesDatabase = mock(Messages.class);
 | 
				
			||||||
        accountsManager  = mock(AccountsManager.class);
 | 
					        accountsManager  = mock(AccountsManager.class);
 | 
				
			||||||
        pubSubManager    = mock(PubSubManager.class);
 | 
					        pubSubManager    = mock(PubSubManager.class);
 | 
				
			||||||
| 
						 | 
					@ -61,7 +62,7 @@ public class RedisClusterMessagePersisterTest extends AbstractRedisClusterTest {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        notificationExecutorService = Executors.newSingleThreadExecutor();
 | 
					        notificationExecutorService = Executors.newSingleThreadExecutor();
 | 
				
			||||||
        messagesCache               = new RedisClusterMessagesCache(getRedisCluster(), notificationExecutorService);
 | 
					        messagesCache               = new RedisClusterMessagesCache(getRedisCluster(), notificationExecutorService);
 | 
				
			||||||
        messagePersister            = new RedisClusterMessagePersister(messagesCache, messagesDatabase, pubSubManager, mock(PushSender.class), accountsManager, PERSIST_DELAY);
 | 
					        messagePersister            = new RedisClusterMessagePersister(messagesCache, messagesDatabase, pubSubManager, mock(PushSender.class), accountsManager, featureFlagsManager, PERSIST_DELAY);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
| 
						 | 
					@ -136,6 +137,7 @@ public class RedisClusterMessagePersisterTest extends AbstractRedisClusterTest {
 | 
				
			||||||
        verify(messagesDatabase, times(queueCount * messagesPerQueue)).store(any(UUID.class), any(MessageProtos.Envelope.class), anyString(), anyLong());
 | 
					        verify(messagesDatabase, times(queueCount * messagesPerQueue)).store(any(UUID.class), any(MessageProtos.Envelope.class), anyString(), anyLong());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @SuppressWarnings("SameParameterValue")
 | 
				
			||||||
    private static String generateRandomQueueNameForSlot(final int slot) {
 | 
					    private static String generateRandomQueueNameForSlot(final int slot) {
 | 
				
			||||||
        final UUID uuid = UUID.randomUUID();
 | 
					        final UUID uuid = UUID.randomUUID();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue