Код-ревью 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 при ошибке.

Что должен найти ревьюер

  1. Ошибкастрока 2
    Очередь в памяти: при выгрузке процесса все неотправленные черновики теряются. Нужна таблица outbox в базе.
  2. Производительностьстрока 6
    GlobalScope.launch на каждое сохранение: параллельные flush отправят одни и те же черновики несколько раз. Нужен один синхронизатор (WorkManager с уникальной работой).
  3. Ошибкастрока 10
    Удаление из списка во время обхода for даст ConcurrentModificationException.
  4. Ошибкастрока 11
    Повтор после обрыва создаст дубль: нет ключа идемпотентности.
  5. Ошибкастрока 11
    Нет обработки ошибок и ретраев с задержкой: первая ошибка прервёт всю отправку.
  6. Ошибкастрока 17
    Сравнение времени устройства с серверным: из-за расхождения часов изменения будут тихо теряться. Нужны версии или серверное время.

Разбор

Надёжная схема: черновик пишется в базу вместе с операцией в outbox (в одной транзакции), уникальная работа WorkManager с ограничением «есть сеть» вычитывает операции по порядку, отправляет с ключом идемпотентности, удаляет после успеха и повторяет с backoff при ошибке. Конфликты разрешаются по версии записи (сервер отвечает 409 на устаревшую версию).

Ответьте сами, а не прочитайте

В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.