Publish "messages persisted" events when unlocking queues after a persistence run

This commit is contained in:
Jon Chambers
2024-11-07 17:19:55 -05:00
committed by Jon Chambers
parent 084607f359
commit 562b495a18
13 changed files with 63 additions and 78 deletions

View File

@@ -58,11 +58,6 @@ public class PubSubClientEventManager extends RedisClusterPubSubAdapter<byte[],
.build()
.toByteArray();
private final byte[] MESSAGES_PERSISTED_EVENT_BYTES = ClientEvent.newBuilder()
.setMessagesPersisted(MessagesPersistedEvent.getDefaultInstance())
.build()
.toByteArray();
@Nullable
private FaultTolerantPubSubClusterConnection<byte[], byte[]> pubSubConnection;
@@ -224,25 +219,6 @@ public class PubSubClientEventManager extends RedisClusterPubSubAdapter<byte[],
});
}
/**
* Publishes an event notifying a specific device that messages have been persisted from short-term to long-term
* storage.
*
* @param accountIdentifier the account identifier for which messages have been persisted
* @param deviceId the ID of the device within the target account
*
* @return a future that completes when the event has been published
*/
public CompletionStage<Void> handleMessagesPersisted(final UUID accountIdentifier, final byte deviceId) {
if (pubSubConnection == null) {
throw new IllegalStateException("Presence manager not started");
}
return pubSubConnection.withPubSubConnection(connection ->
connection.async().spublish(getClientEventChannel(accountIdentifier, deviceId), MESSAGES_PERSISTED_EVENT_BYTES))
.thenRun(Util.NOOP);
}
/**
* Tests whether a client with the given account/device is connected to this presence manager instance.
*

View File

@@ -22,7 +22,6 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicConfiguration;
import org.whispersystems.textsecuregcm.entities.MessageProtos;
import org.whispersystems.textsecuregcm.push.PubSubClientEventManager;
import org.whispersystems.textsecuregcm.util.Util;
import software.amazon.awssdk.services.dynamodb.model.ItemCollectionSizeLimitExceededException;
@@ -31,7 +30,6 @@ public class MessagePersister implements Managed {
private final MessagesCache messagesCache;
private final MessagesManager messagesManager;
private final AccountsManager accountsManager;
private final PubSubClientEventManager pubSubClientEventManager;
private final Duration persistDelay;
@@ -63,9 +61,9 @@ public class MessagePersister implements Managed {
private static final Logger logger = LoggerFactory.getLogger(MessagePersister.class);
public MessagePersister(final MessagesCache messagesCache, final MessagesManager messagesManager,
public MessagePersister(final MessagesCache messagesCache,
final MessagesManager messagesManager,
final AccountsManager accountsManager,
final PubSubClientEventManager pubSubClientEventManager,
final DynamicConfigurationManager<DynamicConfiguration> dynamicConfigurationManager,
final Duration persistDelay,
final int dedicatedProcessWorkerThreadCount
@@ -74,7 +72,6 @@ public class MessagePersister implements Managed {
this.messagesCache = messagesCache;
this.messagesManager = messagesManager;
this.accountsManager = accountsManager;
this.pubSubClientEventManager = pubSubClientEventManager;
this.persistDelay = persistDelay;
this.workerThreads = new Thread[dedicatedProcessWorkerThreadCount];
@@ -211,7 +208,6 @@ public class MessagePersister implements Managed {
maybeUnlink(account, deviceId); // may throw, in which case we'll retry later by the usual mechanism
} finally {
messagesCache.unlockQueueForPersistence(accountUuid, deviceId);
pubSubClientEventManager.handleMessagesPersisted(accountUuid, deviceId);
sample.stop(persistQueueTimer);
}

View File

@@ -125,6 +125,7 @@ public class MessagesCache {
private final MessagesCacheRemoveQueueScript removeQueueScript;
private final MessagesCacheGetQueuesToPersistScript getQueuesToPersistScript;
private final MessagesCacheRemoveRecipientViewFromMrmDataScript removeRecipientViewFromMrmDataScript;
private final MessagesCacheUnlockQueueScript unlockQueueScript;
private final Timer insertTimer = Metrics.timer(name(MessagesCache.class, "insert"));
private final Timer insertSharedMrmPayloadTimer = Metrics.timer(name(MessagesCache.class, "insertSharedMrmPayload"));
@@ -176,7 +177,8 @@ public class MessagesCache {
new MessagesCacheRemoveByGuidScript(redisCluster),
new MessagesCacheRemoveQueueScript(redisCluster),
new MessagesCacheGetQueuesToPersistScript(redisCluster),
new MessagesCacheRemoveRecipientViewFromMrmDataScript(redisCluster)
new MessagesCacheRemoveRecipientViewFromMrmDataScript(redisCluster),
new MessagesCacheUnlockQueueScript(redisCluster)
);
}
@@ -190,8 +192,8 @@ public class MessagesCache {
final MessagesCacheGetItemsScript getItemsScript, final MessagesCacheRemoveByGuidScript removeByGuidScript,
final MessagesCacheRemoveQueueScript removeQueueScript,
final MessagesCacheGetQueuesToPersistScript getQueuesToPersistScript,
final MessagesCacheRemoveRecipientViewFromMrmDataScript removeRecipientViewFromMrmDataScript)
throws IOException {
final MessagesCacheRemoveRecipientViewFromMrmDataScript removeRecipientViewFromMrmDataScript,
final MessagesCacheUnlockQueueScript unlockQueueScript) throws IOException {
this.redisCluster = redisCluster;
this.clock = clock;
@@ -209,6 +211,7 @@ public class MessagesCache {
this.removeQueueScript = removeQueueScript;
this.getQueuesToPersistScript = getQueuesToPersistScript;
this.removeRecipientViewFromMrmDataScript = removeRecipientViewFromMrmDataScript;
this.unlockQueueScript = unlockQueueScript;
}
public boolean insert(final UUID messageGuid,
@@ -599,8 +602,7 @@ public class MessagesCache {
}
void unlockQueueForPersistence(final UUID accountUuid, final byte deviceId) {
redisCluster.useBinaryCluster(
connection -> connection.sync().del(getPersistInProgressKey(accountUuid, deviceId)));
unlockQueueScript.execute(accountUuid, deviceId);
}
static byte[] getMessageQueueKey(final UUID accountUuid, final byte deviceId) {

View File

@@ -0,0 +1,43 @@
/*
* Copyright 2024 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.whispersystems.textsecuregcm.storage;
import io.lettuce.core.ScriptOutputType;
import org.whispersystems.textsecuregcm.push.ClientEvent;
import org.whispersystems.textsecuregcm.push.MessagesPersistedEvent;
import org.whispersystems.textsecuregcm.push.PubSubClientEventManager;
import org.whispersystems.textsecuregcm.redis.ClusterLuaScript;
import org.whispersystems.textsecuregcm.redis.FaultTolerantRedisClusterClient;
import java.io.IOException;
import java.util.List;
import java.util.UUID;
/**
* Unlocks a message queue for persistence/message retrieval.
*/
class MessagesCacheUnlockQueueScript {
private final ClusterLuaScript unlockQueueScript;
private final List<byte[]> MESSAGES_PERSISTED_EVENT_ARGS = List.of(ClientEvent.newBuilder()
.setMessagesPersisted(MessagesPersistedEvent.getDefaultInstance())
.build()
.toByteArray()); // eventPayload
MessagesCacheUnlockQueueScript(final FaultTolerantRedisClusterClient redisCluster) throws IOException {
this.unlockQueueScript =
ClusterLuaScript.fromResource(redisCluster, "lua/unlock_queue.lua", ScriptOutputType.STATUS);
}
void execute(final UUID accountIdentifier, final byte deviceId) {
final List<byte[]> keys = List.of(
MessagesCache.getPersistInProgressKey(accountIdentifier, deviceId), // persistInProgressKey
PubSubClientEventManager.getClientEventChannel(accountIdentifier, deviceId) // eventChannelKey
);
unlockQueueScript.executeBinary(keys, MESSAGES_PERSISTED_EVENT_ARGS);
}
}

View File

@@ -76,7 +76,6 @@ record CommandDependencies(
ReportMessageManager reportMessageManager,
MessagesCache messagesCache,
MessagesManager messagesManager,
PubSubClientEventManager pubSubClientEventManager,
KeysManager keysManager,
APNSender apnSender,
FcmSender fcmSender,
@@ -269,7 +268,6 @@ record CommandDependencies(
reportMessageManager,
messagesCache,
messagesManager,
pubSubClientEventManager,
keys,
apnSender,
fcmSender,

View File

@@ -63,7 +63,6 @@ public class MessagePersisterServiceCommand extends ServerCommand<WhisperServerC
final MessagePersister messagePersister = new MessagePersister(deps.messagesCache(),
deps.messagesManager(),
deps.accountsManager(),
deps.pubSubClientEventManager(),
deps.dynamicConfigurationManager(),
Duration.ofMinutes(configuration.getMessageCacheConfiguration().getPersistDelayMinutes()),
namespace.getInt(WORKER_COUNT));