mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-03-02 23:38:34 +00:00
Prevent infinite archive attachment reconciliation attempts after server storage quota disagreement.
This commit is contained in:
committed by
Michelle Tang
parent
415021eedf
commit
a37209d8ba
@@ -36,7 +36,6 @@ import org.thoughtcrime.securesms.util.RemoteConfig
|
||||
import org.whispersystems.signalservice.api.NetworkResult
|
||||
import org.whispersystems.signalservice.api.archive.ArchiveGetMediaItemsResponse
|
||||
import org.whispersystems.signalservice.api.backup.MediaId
|
||||
import java.lang.RuntimeException
|
||||
import kotlin.time.Duration.Companion.days
|
||||
import kotlin.time.Duration.Companion.hours
|
||||
|
||||
@@ -66,6 +65,20 @@ class ArchiveAttachmentReconciliationJob private constructor(
|
||||
|
||||
private const val CDN_FETCH_LIMIT = 10_000
|
||||
private const val DELETE_BATCH_SIZE = 10_000
|
||||
|
||||
/**
|
||||
* Enqueues a reconciliation job if the retry limit hasn't been exceeded.
|
||||
*
|
||||
* @param forced If true, forces the job run to bypass any sync interval constraints.
|
||||
*/
|
||||
fun enqueueIfRetryAllowed(forced: Boolean) {
|
||||
if (SignalStore.backup.archiveAttachmentReconciliationAttempts < 3) {
|
||||
SignalStore.backup.archiveAttachmentReconciliationAttempts++
|
||||
AppDependencies.jobManager.add(ArchiveAttachmentReconciliationJob(forced = forced))
|
||||
} else {
|
||||
Log.i(TAG, "Skip enqueueing reconciliation job: attempt limit exceeded.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
constructor(forced: Boolean = false) : this(
|
||||
@@ -327,6 +340,7 @@ class ArchiveAttachmentReconciliationJob private constructor(
|
||||
return null to Result.failure()
|
||||
}
|
||||
}
|
||||
|
||||
is NetworkResult.ApplicationError -> {
|
||||
Log.w(TAG, "Failed to list remote media objects due to a crash.", result.getCause())
|
||||
return null to Result.fatalFailure(RuntimeException(result.getCause()))
|
||||
|
||||
@@ -173,7 +173,7 @@ class CopyAttachmentToArchiveJob private constructor(private val attachmentId: A
|
||||
|
||||
Log.i(TAG, "[$attachmentId] Remote storage is full, but our local state indicates that once we reconcile our storage, we should have enough. Enqueuing the reconciliation job and retrying.")
|
||||
SignalStore.backup.remoteStorageGarbageCollectionPending = true
|
||||
AppDependencies.jobManager.add(ArchiveAttachmentReconciliationJob(forced = true))
|
||||
ArchiveAttachmentReconciliationJob.enqueueIfRetryAllowed(forced = true)
|
||||
|
||||
Result.retry(defaultBackoff())
|
||||
}
|
||||
@@ -206,6 +206,7 @@ class CopyAttachmentToArchiveJob private constructor(private val attachmentId: A
|
||||
}
|
||||
|
||||
ArchiveUploadProgress.onAttachmentFinished(attachmentId)
|
||||
SignalStore.backup.archiveAttachmentReconciliationAttempts = 0
|
||||
}
|
||||
|
||||
return result
|
||||
@@ -213,7 +214,7 @@ class CopyAttachmentToArchiveJob private constructor(private val attachmentId: A
|
||||
|
||||
private fun getServerQuota(): ByteSize? {
|
||||
return runBlocking {
|
||||
BackupRepository.getPaidType().successOrThrow()?.storageAllowanceBytes?.bytes
|
||||
BackupRepository.getPaidType().successOrThrow().storageAllowanceBytes?.bytes
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -82,6 +82,7 @@ class BackupValues(store: KeyValueStore) : SignalStoreValues(store) {
|
||||
private const val KEY_BACKUP_EXPIRED_AND_DOWNGRADED = "backup.expired.and.downgraded"
|
||||
private const val KEY_BACKUP_DELETION_STATE = "backup.deletion.state"
|
||||
private const val KEY_REMOTE_STORAGE_GARBAGE_COLLECTION_PENDING = "backup.remoteStorageGarbageCollectionPending"
|
||||
private const val KEY_ARCHIVE_ATTACHMENT_RECONCILIATION_ATTEMPTS = "backup.archiveAttachmentReconciliationAttempts"
|
||||
|
||||
private const val KEY_MEDIA_ROOT_BACKUP_KEY = "backup.mediaRootBackupKey"
|
||||
|
||||
@@ -393,10 +394,25 @@ class BackupValues(store: KeyValueStore) : SignalStoreValues(store) {
|
||||
var remoteStorageGarbageCollectionPending
|
||||
get() = store.getBoolean(KEY_REMOTE_STORAGE_GARBAGE_COLLECTION_PENDING, false)
|
||||
set(value) {
|
||||
store.beginWrite().putBoolean(KEY_REMOTE_STORAGE_GARBAGE_COLLECTION_PENDING, value)
|
||||
store.beginWrite()
|
||||
.putBoolean(KEY_REMOTE_STORAGE_GARBAGE_COLLECTION_PENDING, value)
|
||||
.apply()
|
||||
NoRemoteArchiveGarbageCollectionPendingConstraint.Observer.notifyListeners()
|
||||
}
|
||||
|
||||
/**
|
||||
* Tracks archive attachment reconciliation attempts to prevent infinite retries when we disagree with the server about available storage space.
|
||||
*/
|
||||
var archiveAttachmentReconciliationAttempts: Int
|
||||
get() {
|
||||
return store.getInteger(KEY_ARCHIVE_ATTACHMENT_RECONCILIATION_ATTEMPTS, 0)
|
||||
}
|
||||
set(value) {
|
||||
store.beginWrite()
|
||||
.putInteger(KEY_ARCHIVE_ATTACHMENT_RECONCILIATION_ATTEMPTS, value)
|
||||
.apply()
|
||||
}
|
||||
|
||||
/**
|
||||
* When we are told by the server that we are out of storage space, we should show
|
||||
* UX treatment to make the user aware of this.
|
||||
@@ -416,6 +432,8 @@ class BackupValues(store: KeyValueStore) : SignalStoreValues(store) {
|
||||
.putBoolean(KEY_NOT_ENOUGH_REMOTE_STORAGE_SPACE, false)
|
||||
.putBoolean(KEY_NOT_ENOUGH_REMOTE_STORAGE_SPACE_DISPLAY_SHEET, false)
|
||||
.apply()
|
||||
|
||||
archiveAttachmentReconciliationAttempts = 0
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user