Код-ревью Senior Офлайн и синхронизация обновлено
Код-ревью: синхронизация черновиков (Kotlin)
Вопрос
Найдите проблемы надёжности в синхронизации офлайн-черновиков.
object DraftSync {
private val pending = mutableListOf<Draft>()
fun save(draft: Draft) {
pending.add(draft)
GlobalScope.launch { flush() }
}
suspend fun flush() {
for (d in pending) {
api.createDraft(d)
pending.remove(d)
}
}
fun resolve(local: Draft, remote: Draft): Draft =
if (local.updatedAtDevice > remote.updatedAt) local else remote
}
Коротко
Надёжная схема: черновик пишется в базу вместе с операцией в outbox (в одной транзакции), уникальная работа WorkManager с ограничением «есть сеть» вычитывает операции по порядку, отправляет с ключом идемпотентности, удаляет после успеха и повторяет с backoff при ошибке.
Что должен найти ревьюер
- Ошибкастрока 2Очередь в памяти: при выгрузке процесса все неотправленные черновики теряются. Нужна таблица outbox в базе.
- Производительностьстрока 6
GlobalScope.launchна каждое сохранение: параллельныеflushотправят одни и те же черновики несколько раз. Нужен один синхронизатор (WorkManager с уникальной работой). - Ошибкастрока 10Удаление из списка во время обхода
forдастConcurrentModificationException. - Ошибкастрока 11Повтор после обрыва создаст дубль: нет ключа идемпотентности.
- Ошибкастрока 11Нет обработки ошибок и ретраев с задержкой: первая ошибка прервёт всю отправку.
- Ошибкастрока 17Сравнение времени устройства с серверным: из-за расхождения часов изменения будут тихо теряться. Нужны версии или серверное время.
Разбор
Надёжная схема: черновик пишется в базу вместе с операцией в outbox (в одной транзакции), уникальная работа WorkManager с ограничением «есть сеть» вычитывает операции по порядку, отправляет с ключом идемпотентности, удаляет после успеха и повторяет с backoff при ошибке. Конфликты разрешаются по версии записи (сервер отвечает 409 на устаревшую версию).
Ответьте сами, а не прочитайте
В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.