From 8c84a814396a177387a4616d7cb13c8ace1b86d5 Mon Sep 17 00:00:00 2001 From: Jim Martens Date: Sat, 28 Oct 2023 10:55:25 +0200 Subject: [PATCH] Handle tasks from the past correctly Should only ever apply to tasks from a few seconds ago. Longer downtimes should not happen. --- .../bahnApi/service/TaskScheduler.kt | 62 +++++++++++++++---- 1 file changed, 50 insertions(+), 12 deletions(-) diff --git a/module-server/src/main/kotlin/de/twomartens/timetable/bahnApi/service/TaskScheduler.kt b/module-server/src/main/kotlin/de/twomartens/timetable/bahnApi/service/TaskScheduler.kt index 7044699..1374ab1 100644 --- a/module-server/src/main/kotlin/de/twomartens/timetable/bahnApi/service/TaskScheduler.kt +++ b/module-server/src/main/kotlin/de/twomartens/timetable/bahnApi/service/TaskScheduler.kt @@ -6,36 +6,66 @@ import de.twomartens.timetable.bahnApi.repository.ScheduledFetchTaskRepository import de.twomartens.timetable.bahnApi.tasks.DeleteScheduledTask import de.twomartens.timetable.bahnApi.tasks.FetchTimetableTask import de.twomartens.timetable.bahnApi.tasks.StoreTimetableTask -import de.twomartens.timetable.property.TimeProperties import de.twomartens.timetable.types.HourAtDay import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler import org.springframework.stereotype.Service +import java.time.Clock import java.time.ZonedDateTime +private const val PAST_TASK_EXECUTION_OFFSET = 1 + @Service class TaskScheduler( - private val timeProperties: TimeProperties, + private val clock: Clock, private val threadPoolTaskScheduler: ThreadPoolTaskScheduler, private val threadPoolTaskExecutor: ThreadPoolTaskExecutor, private val bahnApiService: BahnApiService, private val bahnDatabaseService: BahnDatabaseService, private val scheduledFetchTaskRepository: ScheduledFetchTaskRepository ) { - fun scheduleFetchTasks(scheduledTasks: List) { - scheduledTasks.forEach { - val zonedExecutionTime = it.scheduledExecutionDateTime - .atZone(timeProperties.defaultTimeZone) - scheduleDeleteTask(it, zonedExecutionTime) - scheduleFetchTimetableTask(it, zonedExecutionTime) - } - } - fun scheduleStoreTask(timetable: BahnTimetable, hourAtDay: HourAtDay) { val storeTask = StoreTimetableTask(timetable, hourAtDay, bahnDatabaseService) threadPoolTaskExecutor.execute(storeTask) } + fun scheduleFetchTasks(scheduledTasks: List) { + val nowPlus1Minute = ZonedDateTime.now(clock).plusMinutes(1) + scheduleTasksFromThePast(scheduledTasks, nowPlus1Minute) + scheduleTasksFromTheFuture(scheduledTasks, nowPlus1Minute) + } + + private fun scheduleTasksFromThePast( + scheduledTasks: List, + nowPlus1Minute: ZonedDateTime + ) { + val tasksScheduledForPast = scheduledTasks.filter { + val zonedExecutionTime = it.scheduledExecutionDateTime.atZone(clock.zone) + nowPlus1Minute.isAfter(zonedExecutionTime) + } + tasksScheduledForPast.forEach { + val zonedExecutionTime = it.scheduledExecutionDateTime.atZone(clock.zone) + val adjustedExecutionTime = nowPlus1Minute.withOffsetAndSecondsFrom(zonedExecutionTime) + scheduleDeleteTask(it, adjustedExecutionTime) + scheduleFetchTimetableTask(it, adjustedExecutionTime) + } + } + + private fun scheduleTasksFromTheFuture( + scheduledTasks: List, + nowPlus1Minute: ZonedDateTime + ) { + val tasksScheduledForFuture = scheduledTasks.filter { + val zonedExecutionTime = it.scheduledExecutionDateTime.atZone(clock.zone) + nowPlus1Minute.isOnOrBefore(zonedExecutionTime) + } + tasksScheduledForFuture.forEach { + val zonedExecutionTime = it.scheduledExecutionDateTime.atZone(clock.zone) + scheduleDeleteTask(it, zonedExecutionTime) + scheduleFetchTimetableTask(it, zonedExecutionTime) + } + } + private fun scheduleDeleteTask( scheduledFetchTask: ScheduledFetchTask, zonedExecutionTime: ZonedDateTime @@ -53,4 +83,12 @@ class TaskScheduler( bahnApiService, this) threadPoolTaskScheduler.schedule(timetableTask, zonedExecutionTime.toInstant()) } -} \ No newline at end of file + + companion object { + fun ZonedDateTime.withOffsetAndSecondsFrom(other: ZonedDateTime): ZonedDateTime = + this.withSecond(other.second + PAST_TASK_EXECUTION_OFFSET) + + fun ZonedDateTime.isOnOrBefore(other: ZonedDateTime): Boolean = + this.isBefore(other) || this.isEqual(other) + } +}