fix: ssl error & offline teacher schedule

This commit is contained in:
2026-10-07 21:55:53 +03:00
parent af1f374b95
commit ae0fea1ea6
8 changed files with 89 additions and 13 deletions
@@ -33,6 +33,9 @@ interface TeacherScheduleDao {
@Query("DELETE FROM teacher_schedules")
suspend fun deleteAll()
@Query("SELECT lastSyncedAt FROM teacher_schedules WHERE departmentId = :departmentId AND season = :season AND weekStart = :weekStart")
suspend fun lastSyncedAt(departmentId: String, season: String, weekStart: Long): Long?
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertDays(days: List<TeacherDayEntity>): List<Long>
@@ -41,6 +44,7 @@ interface TeacherScheduleDao {
@Transaction
suspend fun replaceSchedule(schedule: TeacherScheduleEntity, days: List<TeacherDayEntity>, lessons: List<TeacherLessonEntity>) {
deleteSchedule(schedule.departmentId, schedule.season.name, schedule.weekStart)
val scheduleId = insertSchedule(schedule)
val daysWithScheduleId = days.map { it.copy(scheduleId = scheduleId) }
deleteDaysForSchedule(scheduleId)
@@ -56,7 +56,7 @@ class TeacherScheduleRepositoryImpl(
scheduleDao.observeDistinctTeachers(period.season.name, period.weekStart.toEpochDay())
.map { names -> names.map { name -> Teacher(name = name) } }
override suspend fun syncPeriod(date: LocalDate): Flow<BulkSyncProgress> = flow {
override suspend fun syncPeriod(date: LocalDate, force: Boolean): Flow<BulkSyncProgress> = flow {
// Unique index (departmentId, season, weekStart) breaks on interleaved
// delete+insert from concurrent syncPeriod() callers.
syncMutex.withLock {
@@ -68,18 +68,27 @@ class TeacherScheduleRepositoryImpl(
return@withLock
}
targets.map { it.season to it.weekStart }
.distinct()
.forEach { (season, weekStart) ->
withContext(Dispatchers.IO) {
scheduleDao.deletePeriod(season.name, weekStart)
}
val now = now()
var skippedCount = 0
val nonSkipped = mutableListOf<DepartmentPeriodEntity>()
for (target in targets) {
val last = withContext(Dispatchers.IO) {
scheduleDao.lastSyncedAt(target.departmentId, target.season.name, target.weekStart)
}
val shouldSkip = !force && last != null && now - last < STALE_WINDOW_MS
if (shouldSkip) {
skippedCount++
} else {
nonSkipped.add(target)
}
}
emit(BulkSyncProgress(total = targets.size, done = skippedCount, failed = 0))
val total = targets.size
val semaphore = Semaphore(PARALLELISM)
val jobs = coroutineScope {
targets.map { target ->
nonSkipped.map { target ->
async {
semaphore.withPermit {
try {
@@ -102,7 +111,7 @@ class TeacherScheduleRepositoryImpl(
}
}
var done = 0
var done = skippedCount
var failed = 0
for (job in jobs) {
if (job.await()) done++ else failed++