Улучшена фоновая синхронизация
This commit is contained in:
@@ -16,6 +16,7 @@ import com.github.nullptroma.wallenc.usecases.RenameStorageUseCase
|
|||||||
import com.github.nullptroma.wallenc.usecases.RunStorageSyncUseCase
|
import com.github.nullptroma.wallenc.usecases.RunStorageSyncUseCase
|
||||||
import com.github.nullptroma.wallenc.usecases.ManageStorageSyncGroupsUseCase
|
import com.github.nullptroma.wallenc.usecases.ManageStorageSyncGroupsUseCase
|
||||||
import com.github.nullptroma.wallenc.usecases.StorageSyncEngine
|
import com.github.nullptroma.wallenc.usecases.StorageSyncEngine
|
||||||
|
import com.github.nullptroma.wallenc.usecases.StorageSyncReadiness
|
||||||
import com.github.nullptroma.wallenc.usecases.StorageFileManagementUseCase
|
import com.github.nullptroma.wallenc.usecases.StorageFileManagementUseCase
|
||||||
import dagger.Module
|
import dagger.Module
|
||||||
import dagger.Provides
|
import dagger.Provides
|
||||||
@@ -104,10 +105,27 @@ class UseCasesModule {
|
|||||||
groupStore: IStorageSyncGroupStore,
|
groupStore: IStorageSyncGroupStore,
|
||||||
): ManageStorageSyncGroupsUseCase = ManageStorageSyncGroupsUseCase(groupStore)
|
): ManageStorageSyncGroupsUseCase = ManageStorageSyncGroupsUseCase(groupStore)
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideStorageSyncReadiness(
|
||||||
|
vaultsManager: IVaultsManager,
|
||||||
|
groupStore: IStorageSyncGroupStore,
|
||||||
|
findStorageUseCase: FindStorageUseCase,
|
||||||
|
): StorageSyncReadiness = StorageSyncReadiness(
|
||||||
|
vaultsManager = vaultsManager,
|
||||||
|
groupStore = groupStore,
|
||||||
|
findStorageUseCase = findStorageUseCase,
|
||||||
|
)
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
fun provideRunStorageSyncUseCase(
|
fun provideRunStorageSyncUseCase(
|
||||||
orchestrator: ITaskOrchestrator,
|
orchestrator: ITaskOrchestrator,
|
||||||
syncEngine: IStorageSyncEngine,
|
syncEngine: IStorageSyncEngine,
|
||||||
): RunStorageSyncUseCase = RunStorageSyncUseCase(orchestrator, syncEngine)
|
syncReadiness: StorageSyncReadiness,
|
||||||
|
): RunStorageSyncUseCase = RunStorageSyncUseCase(
|
||||||
|
orchestrator = orchestrator,
|
||||||
|
syncEngine = syncEngine,
|
||||||
|
syncReadiness = syncReadiness,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
@@ -29,7 +29,7 @@ class StorageSyncScheduler @Inject constructor(
|
|||||||
|
|
||||||
WorkManager.getInstance(app).enqueueUniquePeriodicWork(
|
WorkManager.getInstance(app).enqueueUniquePeriodicWork(
|
||||||
StorageSyncWorker.UNIQUE_WORK_NAME,
|
StorageSyncWorker.UNIQUE_WORK_NAME,
|
||||||
ExistingPeriodicWorkPolicy.KEEP,
|
ExistingPeriodicWorkPolicy.UPDATE,
|
||||||
request,
|
request,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import androidx.work.WorkerParameters
|
|||||||
import com.github.nullptroma.wallenc.usecases.RunStorageSyncUseCase
|
import com.github.nullptroma.wallenc.usecases.RunStorageSyncUseCase
|
||||||
import dagger.assisted.Assisted
|
import dagger.assisted.Assisted
|
||||||
import dagger.assisted.AssistedInject
|
import dagger.assisted.AssistedInject
|
||||||
|
import timber.log.Timber
|
||||||
|
|
||||||
@HiltWorker
|
@HiltWorker
|
||||||
class StorageSyncWorker @AssistedInject constructor(
|
class StorageSyncWorker @AssistedInject constructor(
|
||||||
@@ -16,10 +17,13 @@ class StorageSyncWorker @AssistedInject constructor(
|
|||||||
) : CoroutineWorker(appContext, params) {
|
) : CoroutineWorker(appContext, params) {
|
||||||
|
|
||||||
override suspend fun doWork(): Result {
|
override suspend fun doWork(): Result {
|
||||||
|
Timber.d("Periodic storage sync started (attempt %d)", runAttemptCount)
|
||||||
return runCatching {
|
return runCatching {
|
||||||
syncRunner.runBlocking()
|
syncRunner.runBlocking()
|
||||||
|
Timber.d("Periodic storage sync finished")
|
||||||
Result.success()
|
Result.success()
|
||||||
}.getOrElse {
|
}.getOrElse { error ->
|
||||||
|
Timber.w(error, "Periodic storage sync failed")
|
||||||
Result.retry()
|
Result.retry()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import java.util.concurrent.atomic.AtomicBoolean
|
|||||||
class RunStorageSyncUseCase(
|
class RunStorageSyncUseCase(
|
||||||
private val orchestrator: ITaskOrchestrator,
|
private val orchestrator: ITaskOrchestrator,
|
||||||
private val syncEngine: IStorageSyncEngine,
|
private val syncEngine: IStorageSyncEngine,
|
||||||
|
private val syncReadiness: StorageSyncReadiness,
|
||||||
) {
|
) {
|
||||||
private val running = AtomicBoolean(false)
|
private val running = AtomicBoolean(false)
|
||||||
|
|
||||||
@@ -71,6 +72,7 @@ class RunStorageSyncUseCase(
|
|||||||
}
|
}
|
||||||
|
|
||||||
suspend fun runBlocking() {
|
suspend fun runBlocking() {
|
||||||
|
syncReadiness.awaitReady()
|
||||||
syncEngine.syncAllGroups()
|
syncEngine.syncAllGroups()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user