mirror of
https://github.com/Suwayomi/Tachidesk.git
synced 2025-12-10 14:52:05 +01:00
Fix/initial scheduling of global update (#1416)
* Fix setting initial global update delay In case no update has run yet, and the "last automated update" defaulted to 0, the calculation always resulted in a multiple of the interval. This resulted for e.g., interval 24, to always be scheduled at 00:00. For e.g., interval 6, it was always one of the following times: 00:00, 06:00, 12:00, 18:00; depending on the current system time. * Delete the existing "last automated update time" So that the update will be triggered based on the time the server got started again after the update. * Extract migrations into separate functions * Cleanup migration execution logic
This commit is contained in:
@@ -8,6 +8,8 @@ import suwayomi.tachidesk.manga.model.dataclass.MangaDataClass
|
||||
interface IUpdater {
|
||||
fun getLastUpdateTimestamp(): Long
|
||||
|
||||
fun deleteLastAutomatedUpdateTimestamp()
|
||||
|
||||
fun addCategoriesToUpdateQueue(
|
||||
categories: List<CategoryDataClass>,
|
||||
clear: Boolean?,
|
||||
|
||||
@@ -116,10 +116,24 @@ class Updater : IUpdater {
|
||||
|
||||
override fun getLastUpdateTimestamp(): Long = preferences.getLong(lastUpdateKey, 0)
|
||||
|
||||
fun saveLastUpdateTimestamp() {
|
||||
preferences.edit().putLong(lastUpdateKey, System.currentTimeMillis()).apply()
|
||||
}
|
||||
|
||||
fun getLastAutomatedUpdateTimestamp(): Long = preferences.getLong(lastAutomatedUpdateKey, 0)
|
||||
|
||||
fun saveLastAutomatedUpdateTimestamp() {
|
||||
preferences.edit().putLong(lastAutomatedUpdateKey, System.currentTimeMillis()).apply()
|
||||
}
|
||||
|
||||
override fun deleteLastAutomatedUpdateTimestamp() {
|
||||
preferences.edit().remove(lastAutomatedUpdateKey).apply()
|
||||
}
|
||||
|
||||
private fun autoUpdateTask() {
|
||||
try {
|
||||
val lastAutomatedUpdate = preferences.getLong(lastAutomatedUpdateKey, 0)
|
||||
preferences.edit().putLong(lastAutomatedUpdateKey, System.currentTimeMillis()).apply()
|
||||
val lastAutomatedUpdate = getLastAutomatedUpdateTimestamp()
|
||||
saveLastAutomatedUpdateTimestamp()
|
||||
|
||||
if (getStatus().isRunning) {
|
||||
logger.debug { "Global update is already in progress" }
|
||||
@@ -150,12 +164,23 @@ class Updater : IUpdater {
|
||||
serverConfig.globalUpdateInterval.value.hours
|
||||
.coerceAtLeast(6.hours)
|
||||
.inWholeMilliseconds
|
||||
val lastAutomatedUpdate = preferences.getLong(lastAutomatedUpdateKey, 0)
|
||||
val timeToNextExecution = (updateInterval - (System.currentTimeMillis() - lastAutomatedUpdate)).mod(updateInterval)
|
||||
val lastAutomatedUpdate = getLastAutomatedUpdateTimestamp()
|
||||
val isInitialScheduling = lastAutomatedUpdate == 0L
|
||||
|
||||
val timeToNextExecution =
|
||||
if (!isInitialScheduling) {
|
||||
(updateInterval - (System.currentTimeMillis() - lastAutomatedUpdate)).mod(updateInterval)
|
||||
} else {
|
||||
updateInterval
|
||||
}
|
||||
|
||||
if (isInitialScheduling) {
|
||||
saveLastAutomatedUpdateTimestamp()
|
||||
}
|
||||
|
||||
val wasPreviousUpdateTriggered =
|
||||
System.currentTimeMillis() - (
|
||||
if (lastAutomatedUpdate > 0) lastAutomatedUpdate else System.currentTimeMillis()
|
||||
if (!isInitialScheduling) lastAutomatedUpdate else System.currentTimeMillis()
|
||||
) < updateInterval
|
||||
if (!wasPreviousUpdateTriggered) {
|
||||
GlobalScope.launch {
|
||||
@@ -316,7 +341,7 @@ class Updater : IUpdater {
|
||||
clear: Boolean?,
|
||||
forceAll: Boolean,
|
||||
) {
|
||||
preferences.edit().putLong(lastUpdateKey, System.currentTimeMillis()).apply()
|
||||
saveLastUpdateTimestamp()
|
||||
|
||||
if (clear == true) {
|
||||
reset()
|
||||
|
||||
@@ -3,10 +3,13 @@ package suwayomi.tachidesk.server
|
||||
import android.app.Application
|
||||
import android.content.Context
|
||||
import io.github.oshai.kotlinlogging.KotlinLogging
|
||||
import suwayomi.tachidesk.manga.impl.update.IUpdater
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.io.File
|
||||
import java.util.prefs.Preferences
|
||||
import kotlin.collections.isNotEmpty
|
||||
import kotlin.collections.orEmpty
|
||||
|
||||
private fun migratePreferences(
|
||||
parent: String?,
|
||||
@@ -43,9 +46,50 @@ private fun migratePreferences(
|
||||
}
|
||||
}
|
||||
|
||||
const val MIGRATION_VERSION = 1
|
||||
private fun migratePreferencesToNewXmlFileBasedStorage() {
|
||||
// Migrate from old preferences api
|
||||
val prefRootNode = "suwayomi/tachidesk"
|
||||
val isMigrationRequired = Preferences.userRoot().nodeExists(prefRootNode)
|
||||
if (isMigrationRequired) {
|
||||
val preferences = Preferences.userRoot().node(prefRootNode)
|
||||
migratePreferences(null, preferences)
|
||||
preferences.removeNode()
|
||||
}
|
||||
}
|
||||
|
||||
private fun migrateMangaDownloadDir(applicationDirs: ApplicationDirs) {
|
||||
val oldMangaDownloadDir = File(applicationDirs.downloadsRoot)
|
||||
val newMangaDownloadDir = File(applicationDirs.mangaDownloadsRoot)
|
||||
val downloadDirs = oldMangaDownloadDir.listFiles().orEmpty()
|
||||
|
||||
val moveDownloadsToNewFolder = !newMangaDownloadDir.exists() && downloadDirs.isNotEmpty()
|
||||
if (moveDownloadsToNewFolder) {
|
||||
newMangaDownloadDir.mkdirs()
|
||||
|
||||
for (downloadDir in downloadDirs) {
|
||||
if (downloadDir == File(applicationDirs.thumbnailDownloadsRoot)) {
|
||||
continue
|
||||
}
|
||||
|
||||
downloadDir.renameTo(File(newMangaDownloadDir, downloadDir.name))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val MIGRATIONS =
|
||||
listOf<Pair<String, (ApplicationDirs) -> Unit>>(
|
||||
"InitialMigration" to { applicationDirs ->
|
||||
migrateMangaDownloadDir(applicationDirs)
|
||||
migratePreferencesToNewXmlFileBasedStorage()
|
||||
},
|
||||
"FixGlobalUpdateScheduling" to {
|
||||
Injekt.get<IUpdater>().deleteLastAutomatedUpdateTimestamp()
|
||||
},
|
||||
)
|
||||
|
||||
fun runMigrations(applicationDirs: ApplicationDirs) {
|
||||
val logger = KotlinLogging.logger("Migration")
|
||||
|
||||
val migrationPreferences =
|
||||
Injekt
|
||||
.get<Application>()
|
||||
@@ -54,36 +98,22 @@ fun runMigrations(applicationDirs: ApplicationDirs) {
|
||||
Context.MODE_PRIVATE,
|
||||
)
|
||||
val version = migrationPreferences.getInt("version", 0)
|
||||
val logger = KotlinLogging.logger("Migration")
|
||||
logger.info { "Running migrations, previous version $version, target version $MIGRATION_VERSION" }
|
||||
|
||||
if (version < 1) {
|
||||
logger.info { "Running migration for version: 1" }
|
||||
val oldMangaDownloadDir = File(applicationDirs.downloadsRoot)
|
||||
val newMangaDownloadDir = File(applicationDirs.mangaDownloadsRoot)
|
||||
val downloadDirs = oldMangaDownloadDir.listFiles().orEmpty()
|
||||
logger.info { "Running migrations, previous version $version, target version ${MIGRATIONS.size}" }
|
||||
|
||||
val moveDownloadsToNewFolder = !newMangaDownloadDir.exists() && downloadDirs.isNotEmpty()
|
||||
if (moveDownloadsToNewFolder) {
|
||||
newMangaDownloadDir.mkdirs()
|
||||
MIGRATIONS.forEachIndexed { index, (migrationName, migrationFunction) ->
|
||||
val migrationVersion = index + 1
|
||||
|
||||
for (downloadDir in downloadDirs) {
|
||||
if (downloadDir == File(applicationDirs.thumbnailDownloadsRoot)) {
|
||||
continue
|
||||
}
|
||||
|
||||
downloadDir.renameTo(File(newMangaDownloadDir, downloadDir.name))
|
||||
}
|
||||
val isMigrationRequired = version < migrationVersion
|
||||
if (!isMigrationRequired) {
|
||||
logger.info { "Skipping migration version $migrationVersion: $migrationName" }
|
||||
return@forEachIndexed
|
||||
}
|
||||
|
||||
// Migrate from old preferences api
|
||||
val prefRootNode = "suwayomi/tachidesk"
|
||||
val isMigrationRequired = Preferences.userRoot().nodeExists(prefRootNode)
|
||||
if (isMigrationRequired) {
|
||||
val preferences = Preferences.userRoot().node(prefRootNode)
|
||||
migratePreferences(null, preferences)
|
||||
preferences.removeNode()
|
||||
}
|
||||
logger.info { "Running migration version $migrationVersion: $migrationName" }
|
||||
|
||||
migrationFunction(applicationDirs)
|
||||
|
||||
migrationPreferences.edit().putInt("version", migrationVersion).apply()
|
||||
}
|
||||
migrationPreferences.edit().putInt("version", MIGRATION_VERSION).apply()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user