From 9ea88855f27a8b80dadcc53991e79608ea80d7c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9F=D1=8B=D1=82=D0=BA=D0=BE=D0=B2=20=D0=A0=D0=BE=D0=BC?= =?UTF-8?q?=D0=B0=D0=BD?= Date: Mon, 18 May 2026 17:48:33 +0300 Subject: [PATCH] =?UTF-8?q?=D0=A3=D0=BB=D1=83=D1=87=D1=88=D0=B5=D0=BD?= =?UTF-8?q?=D0=B0=20=D1=84=D0=BE=D0=BD=D0=BE=D0=B2=D0=B0=D1=8F=20=D1=81?= =?UTF-8?q?=D0=B8=D0=BD=D1=85=D1=80=D0=BE=D0=BD=D0=B8=D0=B7=D0=B0=D1=86?= =?UTF-8?q?=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/di/modules/domain/UseCasesModule.kt | 20 +++++++- .../wallenc/app/sync/StorageSyncScheduler.kt | 2 +- .../wallenc/app/sync/StorageSyncWorker.kt | 6 ++- .../wallenc/usecases/RunStorageSyncUseCase.kt | 2 + .../wallenc/usecases/StorageSyncReadiness.kt | 49 +++++++++++++++++++ 5 files changed, 76 insertions(+), 3 deletions(-) create mode 100644 usecases/src/main/java/com/github/nullptroma/wallenc/usecases/StorageSyncReadiness.kt diff --git a/app/src/main/java/com/github/nullptroma/wallenc/app/di/modules/domain/UseCasesModule.kt b/app/src/main/java/com/github/nullptroma/wallenc/app/di/modules/domain/UseCasesModule.kt index c990bae..a0e438c 100644 --- a/app/src/main/java/com/github/nullptroma/wallenc/app/di/modules/domain/UseCasesModule.kt +++ b/app/src/main/java/com/github/nullptroma/wallenc/app/di/modules/domain/UseCasesModule.kt @@ -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, + ) } \ No newline at end of file diff --git a/app/src/main/java/com/github/nullptroma/wallenc/app/sync/StorageSyncScheduler.kt b/app/src/main/java/com/github/nullptroma/wallenc/app/sync/StorageSyncScheduler.kt index ae54f84..f318b6d 100644 --- a/app/src/main/java/com/github/nullptroma/wallenc/app/sync/StorageSyncScheduler.kt +++ b/app/src/main/java/com/github/nullptroma/wallenc/app/sync/StorageSyncScheduler.kt @@ -29,7 +29,7 @@ class StorageSyncScheduler @Inject constructor( WorkManager.getInstance(app).enqueueUniquePeriodicWork( StorageSyncWorker.UNIQUE_WORK_NAME, - ExistingPeriodicWorkPolicy.KEEP, + ExistingPeriodicWorkPolicy.UPDATE, request, ) } diff --git a/app/src/main/java/com/github/nullptroma/wallenc/app/sync/StorageSyncWorker.kt b/app/src/main/java/com/github/nullptroma/wallenc/app/sync/StorageSyncWorker.kt index df28a0b..f9c2ca3 100644 --- a/app/src/main/java/com/github/nullptroma/wallenc/app/sync/StorageSyncWorker.kt +++ b/app/src/main/java/com/github/nullptroma/wallenc/app/sync/StorageSyncWorker.kt @@ -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() } } diff --git a/usecases/src/main/java/com/github/nullptroma/wallenc/usecases/RunStorageSyncUseCase.kt b/usecases/src/main/java/com/github/nullptroma/wallenc/usecases/RunStorageSyncUseCase.kt index 6bacf00..53e9258 100644 --- a/usecases/src/main/java/com/github/nullptroma/wallenc/usecases/RunStorageSyncUseCase.kt +++ b/usecases/src/main/java/com/github/nullptroma/wallenc/usecases/RunStorageSyncUseCase.kt @@ -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() } } diff --git a/usecases/src/main/java/com/github/nullptroma/wallenc/usecases/StorageSyncReadiness.kt b/usecases/src/main/java/com/github/nullptroma/wallenc/usecases/StorageSyncReadiness.kt new file mode 100644 index 0000000..1c415ee --- /dev/null +++ b/usecases/src/main/java/com/github/nullptroma/wallenc/usecases/StorageSyncReadiness.kt @@ -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 + } +}