Drop the old `AccountCleaner`
This commit is contained in:
parent
c3c7329ebb
commit
bc35278684
|
@ -1,66 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2013-2020 Signal Messenger, LLC
|
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
*/
|
|
||||||
package org.whispersystems.textsecuregcm.storage;
|
|
||||||
|
|
||||||
import static org.whispersystems.textsecuregcm.metrics.MetricsUtil.name;
|
|
||||||
|
|
||||||
import io.micrometer.core.instrument.Counter;
|
|
||||||
import io.micrometer.core.instrument.Metrics;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
public class AccountCleaner extends AccountDatabaseCrawlerListener {
|
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(AccountCleaner.class);
|
|
||||||
|
|
||||||
private static final Counter DELETED_ACCOUNT_COUNTER = Metrics.counter(name(AccountCleaner.class, "deletedAccounts"));
|
|
||||||
|
|
||||||
private final AccountsManager accountsManager;
|
|
||||||
|
|
||||||
public AccountCleaner(final AccountsManager accountsManager) {
|
|
||||||
this.accountsManager = accountsManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCrawlStart() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCrawlEnd() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onCrawlChunk(Optional<UUID> fromUuid, List<Account> chunkAccounts) {
|
|
||||||
final List<CompletableFuture<Void>> deletionFutures = chunkAccounts.stream()
|
|
||||||
.filter(AccountCleaner::isExpired)
|
|
||||||
.map(account -> accountsManager.delete(account, AccountsManager.DeletionReason.EXPIRED)
|
|
||||||
.whenComplete((ignored, throwable) -> {
|
|
||||||
if (throwable != null) {
|
|
||||||
log.warn("Failed to delete account {}", account.getUuid(), throwable);
|
|
||||||
} else {
|
|
||||||
DELETED_ACCOUNT_COUNTER.increment();
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
.toList();
|
|
||||||
|
|
||||||
try {
|
|
||||||
CompletableFuture.allOf(deletionFutures.toArray(new CompletableFuture[0]))
|
|
||||||
.orTimeout(10, TimeUnit.MINUTES)
|
|
||||||
.join();
|
|
||||||
} catch (final Exception e) {
|
|
||||||
log.debug("Failed to delete one or more accounts in chunk", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean isExpired(Account account) {
|
|
||||||
return account.getLastSeen() + TimeUnit.DAYS.toMillis(180) < System.currentTimeMillis();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -25,7 +25,6 @@ import org.whispersystems.textsecuregcm.WhisperServerConfiguration;
|
||||||
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicConfiguration;
|
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicConfiguration;
|
||||||
import org.whispersystems.textsecuregcm.metrics.MetricsUtil;
|
import org.whispersystems.textsecuregcm.metrics.MetricsUtil;
|
||||||
import org.whispersystems.textsecuregcm.redis.FaultTolerantRedisCluster;
|
import org.whispersystems.textsecuregcm.redis.FaultTolerantRedisCluster;
|
||||||
import org.whispersystems.textsecuregcm.storage.AccountCleaner;
|
|
||||||
import org.whispersystems.textsecuregcm.storage.AccountDatabaseCrawler;
|
import org.whispersystems.textsecuregcm.storage.AccountDatabaseCrawler;
|
||||||
import org.whispersystems.textsecuregcm.storage.AccountDatabaseCrawlerCache;
|
import org.whispersystems.textsecuregcm.storage.AccountDatabaseCrawlerCache;
|
||||||
import org.whispersystems.textsecuregcm.storage.AccountDatabaseCrawlerListener;
|
import org.whispersystems.textsecuregcm.storage.AccountDatabaseCrawlerListener;
|
||||||
|
@ -43,7 +42,6 @@ public class CrawlAccountsCommand extends EnvironmentCommand<WhisperServerConfig
|
||||||
|
|
||||||
public enum CrawlType implements ArgumentType<CrawlType> {
|
public enum CrawlType implements ArgumentType<CrawlType> {
|
||||||
GENERAL_PURPOSE,
|
GENERAL_PURPOSE,
|
||||||
ACCOUNT_CLEANER,
|
|
||||||
;
|
;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -124,17 +122,6 @@ public class CrawlAccountsCommand extends EnvironmentCommand<WhisperServerConfig
|
||||||
configuration.getAccountDatabaseCrawlerConfiguration().getChunkSize()
|
configuration.getAccountDatabaseCrawlerConfiguration().getChunkSize()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
case ACCOUNT_CLEANER -> {
|
|
||||||
final AccountDatabaseCrawlerCache accountDatabaseCrawlerCache = new AccountDatabaseCrawlerCache(
|
|
||||||
cacheCluster, AccountDatabaseCrawlerCache.ACCOUNT_CLEANER_PREFIX);
|
|
||||||
|
|
||||||
yield new AccountDatabaseCrawler("Account cleaner crawler",
|
|
||||||
accountsManager,
|
|
||||||
accountDatabaseCrawlerCache,
|
|
||||||
List.of(new AccountCleaner(accountsManager)),
|
|
||||||
configuration.getAccountDatabaseCrawlerConfiguration().getChunkSize()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
environment.lifecycle().manage(new CommandStopListener(configuration.getCommandStopListener()));
|
environment.lifecycle().manage(new CommandStopListener(configuration.getCommandStopListener()));
|
||||||
|
|
|
@ -1,83 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2013-2022 Signal Messenger, LLC
|
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
*/
|
|
||||||
package org.whispersystems.textsecuregcm.storage;
|
|
||||||
|
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
|
||||||
import static org.mockito.ArgumentMatchers.eq;
|
|
||||||
import static org.mockito.Mockito.mock;
|
|
||||||
import static org.mockito.Mockito.never;
|
|
||||||
import static org.mockito.Mockito.verify;
|
|
||||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
|
||||||
import static org.mockito.Mockito.when;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.whispersystems.textsecuregcm.storage.AccountsManager.DeletionReason;
|
|
||||||
|
|
||||||
class AccountCleanerTest {
|
|
||||||
|
|
||||||
private final AccountsManager accountsManager = mock(AccountsManager.class);
|
|
||||||
|
|
||||||
private final Account deletedDisabledAccount = mock(Account.class);
|
|
||||||
private final Account undeletedDisabledAccount = mock(Account.class);
|
|
||||||
private final Account undeletedEnabledAccount = mock(Account.class);
|
|
||||||
|
|
||||||
private final Device deletedDisabledDevice = mock(Device.class );
|
|
||||||
private final Device undeletedDisabledDevice = mock(Device.class );
|
|
||||||
private final Device undeletedEnabledDevice = mock(Device.class );
|
|
||||||
|
|
||||||
@BeforeEach
|
|
||||||
void setup() {
|
|
||||||
when(accountsManager.delete(any(), any())).thenReturn(CompletableFuture.completedFuture(null));
|
|
||||||
|
|
||||||
when(deletedDisabledDevice.isEnabled()).thenReturn(false);
|
|
||||||
when(deletedDisabledDevice.getGcmId()).thenReturn(null);
|
|
||||||
when(deletedDisabledDevice.getApnId()).thenReturn(null);
|
|
||||||
when(deletedDisabledDevice.getVoipApnId()).thenReturn(null);
|
|
||||||
when(deletedDisabledDevice.getFetchesMessages()).thenReturn(false);
|
|
||||||
when(deletedDisabledAccount.isEnabled()).thenReturn(false);
|
|
||||||
when(deletedDisabledAccount.getLastSeen()).thenReturn(System.currentTimeMillis() - TimeUnit.DAYS.toMillis(1000));
|
|
||||||
when(deletedDisabledAccount.getMasterDevice()).thenReturn(Optional.of(deletedDisabledDevice));
|
|
||||||
when(deletedDisabledAccount.getNumber()).thenReturn("+14151231234");
|
|
||||||
when(deletedDisabledAccount.getUuid()).thenReturn(UUID.randomUUID());
|
|
||||||
|
|
||||||
when(undeletedDisabledDevice.isEnabled()).thenReturn(false);
|
|
||||||
when(undeletedDisabledDevice.getGcmId()).thenReturn("foo");
|
|
||||||
when(undeletedDisabledAccount.isEnabled()).thenReturn(false);
|
|
||||||
when(undeletedDisabledAccount.getLastSeen()).thenReturn(System.currentTimeMillis() - TimeUnit.DAYS.toMillis(181));
|
|
||||||
when(undeletedDisabledAccount.getMasterDevice()).thenReturn(Optional.of(undeletedDisabledDevice));
|
|
||||||
when(undeletedDisabledAccount.getNumber()).thenReturn("+14152222222");
|
|
||||||
when(undeletedDisabledAccount.getUuid()).thenReturn(UUID.randomUUID());
|
|
||||||
|
|
||||||
when(undeletedEnabledDevice.isEnabled()).thenReturn(true);
|
|
||||||
when(undeletedEnabledDevice.getApnId()).thenReturn("bar");
|
|
||||||
when(undeletedEnabledAccount.isEnabled()).thenReturn(true);
|
|
||||||
when(undeletedEnabledAccount.getMasterDevice()).thenReturn(Optional.of(undeletedEnabledDevice));
|
|
||||||
when(undeletedEnabledAccount.getNumber()).thenReturn("+14153333333");
|
|
||||||
when(undeletedEnabledAccount.getLastSeen()).thenReturn(System.currentTimeMillis() - TimeUnit.DAYS.toMillis(179));
|
|
||||||
when(undeletedEnabledAccount.getUuid()).thenReturn(UUID.randomUUID());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testAccounts() {
|
|
||||||
AccountCleaner accountCleaner = new AccountCleaner(accountsManager);
|
|
||||||
accountCleaner.onCrawlStart();
|
|
||||||
accountCleaner.timeAndProcessCrawlChunk(Optional.empty(),
|
|
||||||
Arrays.asList(deletedDisabledAccount, undeletedDisabledAccount, undeletedEnabledAccount));
|
|
||||||
accountCleaner.onCrawlEnd();
|
|
||||||
|
|
||||||
verify(accountsManager).delete(deletedDisabledAccount, DeletionReason.EXPIRED);
|
|
||||||
verify(accountsManager).delete(undeletedDisabledAccount, DeletionReason.EXPIRED);
|
|
||||||
verify(accountsManager, never()).delete(eq(undeletedEnabledAccount), any());
|
|
||||||
|
|
||||||
verifyNoMoreInteractions(accountsManager);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
Loading…
Reference in New Issue