Always expose sequential fluxes to account crawlers
This commit is contained in:
parent
cca747a1f6
commit
5b0fcbe854
|
@ -45,7 +45,6 @@ import org.whispersystems.textsecuregcm.util.SystemMapper;
|
||||||
import org.whispersystems.textsecuregcm.util.UUIDUtil;
|
import org.whispersystems.textsecuregcm.util.UUIDUtil;
|
||||||
import org.whispersystems.textsecuregcm.util.Util;
|
import org.whispersystems.textsecuregcm.util.Util;
|
||||||
import reactor.core.publisher.Flux;
|
import reactor.core.publisher.Flux;
|
||||||
import reactor.core.publisher.ParallelFlux;
|
|
||||||
import reactor.core.scheduler.Scheduler;
|
import reactor.core.scheduler.Scheduler;
|
||||||
import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient;
|
import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient;
|
||||||
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
|
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
|
||||||
|
@ -1058,7 +1057,7 @@ public class Accounts extends AbstractDynamoDbStore {
|
||||||
.thenRun(() -> sample.stop(DELETE_TIMER));
|
.thenRun(() -> sample.stop(DELETE_TIMER));
|
||||||
}
|
}
|
||||||
|
|
||||||
ParallelFlux<Account> getAll(final int segments, final Scheduler scheduler) {
|
Flux<Account> getAll(final int segments, final Scheduler scheduler) {
|
||||||
if (segments < 1) {
|
if (segments < 1) {
|
||||||
throw new IllegalArgumentException("Total number of segments must be positive");
|
throw new IllegalArgumentException("Total number of segments must be positive");
|
||||||
}
|
}
|
||||||
|
@ -1073,7 +1072,8 @@ public class Accounts extends AbstractDynamoDbStore {
|
||||||
.totalSegments(segments)
|
.totalSegments(segments)
|
||||||
.build())
|
.build())
|
||||||
.items()
|
.items()
|
||||||
.map(Accounts::fromItem));
|
.map(Accounts::fromItem))
|
||||||
|
.sequential();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
|
|
|
@ -69,7 +69,7 @@ import org.whispersystems.textsecuregcm.util.ExceptionUtils;
|
||||||
import org.whispersystems.textsecuregcm.util.Pair;
|
import org.whispersystems.textsecuregcm.util.Pair;
|
||||||
import org.whispersystems.textsecuregcm.util.SystemMapper;
|
import org.whispersystems.textsecuregcm.util.SystemMapper;
|
||||||
import org.whispersystems.textsecuregcm.util.Util;
|
import org.whispersystems.textsecuregcm.util.Util;
|
||||||
import reactor.core.publisher.ParallelFlux;
|
import reactor.core.publisher.Flux;
|
||||||
import reactor.core.scheduler.Scheduler;
|
import reactor.core.scheduler.Scheduler;
|
||||||
import software.amazon.awssdk.services.dynamodb.model.TransactWriteItem;
|
import software.amazon.awssdk.services.dynamodb.model.TransactWriteItem;
|
||||||
|
|
||||||
|
@ -940,7 +940,7 @@ public class AccountsManager {
|
||||||
return accounts.findRecentlyDeletedE164(uuid);
|
return accounts.findRecentlyDeletedE164(uuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ParallelFlux<Account> streamAllFromDynamo(final int segments, final Scheduler scheduler) {
|
public Flux<Account> streamAllFromDynamo(final int segments, final Scheduler scheduler) {
|
||||||
return accounts.getAll(segments, scheduler);
|
return accounts.getAll(segments, scheduler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ import org.whispersystems.textsecuregcm.WhisperServerConfiguration;
|
||||||
import org.whispersystems.textsecuregcm.metrics.MetricsUtil;
|
import org.whispersystems.textsecuregcm.metrics.MetricsUtil;
|
||||||
import org.whispersystems.textsecuregcm.storage.Account;
|
import org.whispersystems.textsecuregcm.storage.Account;
|
||||||
import org.whispersystems.textsecuregcm.util.logging.UncaughtExceptionHandler;
|
import org.whispersystems.textsecuregcm.util.logging.UncaughtExceptionHandler;
|
||||||
import reactor.core.publisher.ParallelFlux;
|
import reactor.core.publisher.Flux;
|
||||||
import reactor.core.scheduler.Schedulers;
|
import reactor.core.scheduler.Schedulers;
|
||||||
|
|
||||||
public abstract class AbstractSinglePassCrawlAccountsCommand extends EnvironmentCommand<WhisperServerConfiguration> {
|
public abstract class AbstractSinglePassCrawlAccountsCommand extends EnvironmentCommand<WhisperServerConfiguration> {
|
||||||
|
@ -103,5 +103,5 @@ public abstract class AbstractSinglePassCrawlAccountsCommand extends Environment
|
||||||
logger.error("Unhandled error", throwable);
|
logger.error("Unhandled error", throwable);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract void crawlAccounts(final ParallelFlux<Account> accounts);
|
protected abstract void crawlAccounts(final Flux<Account> accounts);
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,6 @@ import org.whispersystems.textsecuregcm.storage.Account;
|
||||||
import org.whispersystems.textsecuregcm.storage.KeysManager;
|
import org.whispersystems.textsecuregcm.storage.KeysManager;
|
||||||
import reactor.core.publisher.Flux;
|
import reactor.core.publisher.Flux;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
import reactor.core.publisher.ParallelFlux;
|
|
||||||
import reactor.util.function.Tuple3;
|
import reactor.util.function.Tuple3;
|
||||||
import reactor.util.function.Tuples;
|
import reactor.util.function.Tuples;
|
||||||
import reactor.util.retry.Retry;
|
import reactor.util.retry.Retry;
|
||||||
|
@ -63,13 +62,12 @@ public class MigrateSignedECPreKeysCommand extends AbstractSinglePassCrawlAccoun
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void crawlAccounts(final ParallelFlux<Account> accounts) {
|
protected void crawlAccounts(final Flux<Account> accounts) {
|
||||||
final KeysManager keysManager = getCommandDependencies().keysManager();
|
final KeysManager keysManager = getCommandDependencies().keysManager();
|
||||||
final int maxConcurrency = getNamespace().getInt(MAX_CONCURRENCY_ARGUMENT);
|
final int maxConcurrency = getNamespace().getInt(MAX_CONCURRENCY_ARGUMENT);
|
||||||
final int bufferSize = getNamespace().getInt(BUFFER_ARGUMENT);
|
final int bufferSize = getNamespace().getInt(BUFFER_ARGUMENT);
|
||||||
|
|
||||||
accounts
|
accounts
|
||||||
.sequential()
|
|
||||||
.flatMap(account -> Flux.fromIterable(account.getDevices())
|
.flatMap(account -> Flux.fromIterable(account.getDevices())
|
||||||
.flatMap(device -> Flux.fromArray(IdentityType.values())
|
.flatMap(device -> Flux.fromArray(IdentityType.values())
|
||||||
.filter(identityType -> device.getSignedPreKey(identityType) != null)
|
.filter(identityType -> device.getSignedPreKey(identityType) != null)
|
||||||
|
|
|
@ -20,8 +20,8 @@ import org.whispersystems.textsecuregcm.metrics.MetricsUtil;
|
||||||
import org.whispersystems.textsecuregcm.metrics.UserAgentTagUtil;
|
import org.whispersystems.textsecuregcm.metrics.UserAgentTagUtil;
|
||||||
import org.whispersystems.textsecuregcm.storage.Account;
|
import org.whispersystems.textsecuregcm.storage.Account;
|
||||||
import org.whispersystems.textsecuregcm.storage.Device;
|
import org.whispersystems.textsecuregcm.storage.Device;
|
||||||
|
import reactor.core.publisher.Flux;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
import reactor.core.publisher.ParallelFlux;
|
|
||||||
|
|
||||||
public class ProcessPushNotificationFeedbackCommand extends AbstractSinglePassCrawlAccountsCommand {
|
public class ProcessPushNotificationFeedbackCommand extends AbstractSinglePassCrawlAccountsCommand {
|
||||||
|
|
||||||
|
@ -62,12 +62,11 @@ public class ProcessPushNotificationFeedbackCommand extends AbstractSinglePassCr
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void crawlAccounts(final ParallelFlux<Account> accounts) {
|
protected void crawlAccounts(final Flux<Account> accounts) {
|
||||||
final boolean isDryRun = getNamespace().getBoolean(DRY_RUN_ARGUMENT);
|
final boolean isDryRun = getNamespace().getBoolean(DRY_RUN_ARGUMENT);
|
||||||
|
|
||||||
accounts
|
accounts
|
||||||
.filter(account -> account.getDevices().stream().anyMatch(this::deviceNeedsUpdate))
|
.filter(account -> account.getDevices().stream().anyMatch(this::deviceNeedsUpdate))
|
||||||
.sequential()
|
|
||||||
.flatMap(account -> {
|
.flatMap(account -> {
|
||||||
account.getDevices().stream()
|
account.getDevices().stream()
|
||||||
.filter(this::deviceNeedsUpdate)
|
.filter(this::deviceNeedsUpdate)
|
||||||
|
|
|
@ -19,7 +19,7 @@ import org.slf4j.LoggerFactory;
|
||||||
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 reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
import reactor.core.publisher.ParallelFlux;
|
import reactor.core.publisher.Flux;
|
||||||
|
|
||||||
public class RemoveExpiredAccountsCommand extends AbstractSinglePassCrawlAccountsCommand {
|
public class RemoveExpiredAccountsCommand extends AbstractSinglePassCrawlAccountsCommand {
|
||||||
|
|
||||||
|
@ -57,13 +57,12 @@ public class RemoveExpiredAccountsCommand extends AbstractSinglePassCrawlAccount
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void crawlAccounts(final ParallelFlux<Account> accounts) {
|
protected void crawlAccounts(final Flux<Account> accounts) {
|
||||||
final boolean isDryRun = getNamespace().getBoolean(DRY_RUN_ARGUMENT);
|
final boolean isDryRun = getNamespace().getBoolean(DRY_RUN_ARGUMENT);
|
||||||
final Counter deletedAccountCounter =
|
final Counter deletedAccountCounter =
|
||||||
Metrics.counter(DELETED_ACCOUNT_COUNTER_NAME, "dryRun", String.valueOf(isDryRun));
|
Metrics.counter(DELETED_ACCOUNT_COUNTER_NAME, "dryRun", String.valueOf(isDryRun));
|
||||||
|
|
||||||
accounts.filter(this::isExpired)
|
accounts.filter(this::isExpired)
|
||||||
.sequential()
|
|
||||||
.flatMap(expiredAccount -> {
|
.flatMap(expiredAccount -> {
|
||||||
final Mono<Void> deleteAccountMono = isDryRun
|
final Mono<Void> deleteAccountMono = isDryRun
|
||||||
? Mono.empty()
|
? Mono.empty()
|
||||||
|
|
|
@ -665,7 +665,7 @@ class AccountsTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
final List<Account> retrievedAccounts =
|
final List<Account> retrievedAccounts =
|
||||||
accounts.getAll(2, Schedulers.parallel()).sequential().collectList().block();
|
accounts.getAll(2, Schedulers.parallel()).collectList().block();
|
||||||
|
|
||||||
assertNotNull(retrievedAccounts);
|
assertNotNull(retrievedAccounts);
|
||||||
assertEquals(expectedAccounts.stream().map(Account::getUuid).collect(Collectors.toSet()),
|
assertEquals(expectedAccounts.stream().map(Account::getUuid).collect(Collectors.toSet()),
|
||||||
|
|
|
@ -124,8 +124,7 @@ class ProcessPushNotificationFeedbackCommandTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
processPushNotificationFeedbackCommand.crawlAccounts(
|
processPushNotificationFeedbackCommand.crawlAccounts(
|
||||||
Flux.just(accountWithActiveDevice, accountWithUninstalledDevice, accountWithAlreadyDisabledUninstalledDevice)
|
Flux.just(accountWithActiveDevice, accountWithUninstalledDevice, accountWithAlreadyDisabledUninstalledDevice));
|
||||||
.parallel());
|
|
||||||
|
|
||||||
if (isDryRun) {
|
if (isDryRun) {
|
||||||
verify(accountsManager, never()).updateAsync(any(), any());
|
verify(accountsManager, never()).updateAsync(any(), any());
|
||||||
|
|
|
@ -73,7 +73,7 @@ class RemoveExpiredAccountsCommandTest {
|
||||||
when(expiredAccount.getLastSeen())
|
when(expiredAccount.getLastSeen())
|
||||||
.thenReturn(clock.instant().minus(RemoveExpiredAccountsCommand.MAX_IDLE_DURATION).minusMillis(1).toEpochMilli());
|
.thenReturn(clock.instant().minus(RemoveExpiredAccountsCommand.MAX_IDLE_DURATION).minusMillis(1).toEpochMilli());
|
||||||
|
|
||||||
removeExpiredAccountsCommand.crawlAccounts(Flux.just(activeAccount, expiredAccount).parallel());
|
removeExpiredAccountsCommand.crawlAccounts(Flux.just(activeAccount, expiredAccount));
|
||||||
|
|
||||||
if (isDryRun) {
|
if (isDryRun) {
|
||||||
verify(accountsManager, never()).delete(any(), any());
|
verify(accountsManager, never()).delete(any(), any());
|
||||||
|
|
Loading…
Reference in New Issue