Улучшена фоновая синхронизация

This commit is contained in:
2026-05-18 17:48:33 +03:00
parent f99d79fece
commit 9ea88855f2
5 changed files with 76 additions and 3 deletions

View File

@@ -16,6 +16,7 @@ import com.github.nullptroma.wallenc.usecases.RenameStorageUseCase
import com.github.nullptroma.wallenc.usecases.RunStorageSyncUseCase
import com.github.nullptroma.wallenc.usecases.ManageStorageSyncGroupsUseCase
import com.github.nullptroma.wallenc.usecases.StorageSyncEngine
import com.github.nullptroma.wallenc.usecases.StorageSyncReadiness
import com.github.nullptroma.wallenc.usecases.StorageFileManagementUseCase
import dagger.Module
import dagger.Provides
@@ -104,10 +105,27 @@ class UseCasesModule {
groupStore: IStorageSyncGroupStore,
): ManageStorageSyncGroupsUseCase = ManageStorageSyncGroupsUseCase(groupStore)
@Provides
@Singleton
fun provideStorageSyncReadiness(
vaultsManager: IVaultsManager,
groupStore: IStorageSyncGroupStore,
findStorageUseCase: FindStorageUseCase,
): StorageSyncReadiness = StorageSyncReadiness(
vaultsManager = vaultsManager,
groupStore = groupStore,
findStorageUseCase = findStorageUseCase,
)
@Provides
@Singleton
fun provideRunStorageSyncUseCase(
orchestrator: ITaskOrchestrator,
syncEngine: IStorageSyncEngine,
): RunStorageSyncUseCase = RunStorageSyncUseCase(orchestrator, syncEngine)
syncReadiness: StorageSyncReadiness,
): RunStorageSyncUseCase = RunStorageSyncUseCase(
orchestrator = orchestrator,
syncEngine = syncEngine,
syncReadiness = syncReadiness,
)
}

View File

@@ -29,7 +29,7 @@ class StorageSyncScheduler @Inject constructor(
WorkManager.getInstance(app).enqueueUniquePeriodicWork(
StorageSyncWorker.UNIQUE_WORK_NAME,
ExistingPeriodicWorkPolicy.KEEP,
ExistingPeriodicWorkPolicy.UPDATE,
request,
)
}

View File

@@ -7,6 +7,7 @@ import androidx.work.WorkerParameters
import com.github.nullptroma.wallenc.usecases.RunStorageSyncUseCase
import dagger.assisted.Assisted
import dagger.assisted.AssistedInject
import timber.log.Timber
@HiltWorker
class StorageSyncWorker @AssistedInject constructor(
@@ -16,10 +17,13 @@ class StorageSyncWorker @AssistedInject constructor(
) : CoroutineWorker(appContext, params) {
override suspend fun doWork(): Result {
Timber.d("Periodic storage sync started (attempt %d)", runAttemptCount)
return runCatching {
syncRunner.runBlocking()
Timber.d("Periodic storage sync finished")
Result.success()
}.getOrElse {
}.getOrElse { error ->
Timber.w(error, "Periodic storage sync failed")
Result.retry()
}
}

View File

@@ -16,6 +16,7 @@ import java.util.concurrent.atomic.AtomicBoolean
class RunStorageSyncUseCase(
private val orchestrator: ITaskOrchestrator,
private val syncEngine: IStorageSyncEngine,
private val syncReadiness: StorageSyncReadiness,
) {
private val running = AtomicBoolean(false)
@@ -71,6 +72,7 @@ class RunStorageSyncUseCase(
}
suspend fun runBlocking() {
syncReadiness.awaitReady()
syncEngine.syncAllGroups()
}
}

View File

@@ -0,0 +1,49 @@
package com.github.nullptroma.wallenc.usecases
import com.github.nullptroma.wallenc.domain.interfaces.IStorageSyncGroupStore
import com.github.nullptroma.wallenc.domain.interfaces.IVaultsManager
import kotlinx.coroutines.delay
import java.util.UUID
/**
* Ожидание готовности хранилищ перед синхронизацией (холодный старт из WorkManager).
*/
class StorageSyncReadiness(
private val vaultsManager: IVaultsManager,
private val groupStore: IStorageSyncGroupStore,
private val findStorageUseCase: FindStorageUseCase,
) {
suspend fun awaitReady(
timeoutMs: Long = DEFAULT_TIMEOUT_MS,
pollIntervalMs: Long = POLL_INTERVAL_MS,
) {
val groups = groupStore.getGroups()
if (groups.isEmpty()) {
return
}
val requiredUuids = groups.flatMap { it.storageUuids }.toSet()
val deadline = System.currentTimeMillis() + timeoutMs
while (System.currentTimeMillis() < deadline) {
if (!isAnyVaultScanning()) {
break
}
delay(pollIntervalMs)
}
while (System.currentTimeMillis() < deadline) {
if (requiredUuids.all { uuid -> findStorageUseCase.find(uuid) != null }) {
return
}
delay(pollIntervalMs)
}
}
private fun isAnyVaultScanning(): Boolean =
vaultsManager.vaults.value.any { it.storagesScanInProgress.value }
private companion object {
private const val DEFAULT_TIMEOUT_MS = 120_000L
private const val POLL_INTERVAL_MS = 250L
}
}