Мобильные системы в офлайне: как работать без постоянной связи
Офлайн-режим в мобильных приложениях: архитектура автономности
Мобильное приложение может стабильно работать месяцами, пока все пользователи находятся в зоне уверенного приёма сети. Но достаточно сотруднику выйти на склад, спуститься в техническое помещение или приехать на удалённый объект, чтобы привычный сценарий перестал работать. Данные не загружаются, сохранение завершается ошибкой, а результат уже выполненной операции становится неопределённым.
Для корпоративных мобильных систем это не просто проблема доступности интерфейса. Если приложение используется для осмотра оборудования, обработки документов, складских операций, обслуживания объектов или выполнения заданий, потеря связи непосредственно влияет на бизнес-процесс.
Пользователь должен иметь возможность продолжать работу, даже когда сервер временно недоступен. При этом выполненные действия необходимо сохранить, передать после восстановления соединения и согласовать с изменениями, которые могли произойти в центральной системе за время отсутствия связи.
На первый взгляд задача выглядит простой: сохранить данные на устройстве, а затем отправить их на сервер. На практике именно между этими двумя действиями возникают наиболее сложные проблемы. Запрос может выполниться на сервере, но ответ потеряется. Один сотрудник может изменить запись, пока другой работает с её предыдущей версией. Удалённый объект может вернуться после синхронизации, а повторная отправка операции — создать дубликат.
Надёжный офлайн-режим — это архитектура, которая обеспечивает автономную работу, сохраняет историю несинхронизированных изменений и управляемо согласует данные после восстановления связи.
> Чтобы реализовать её правильно, необходимо спроектировать не только локальное хранение, но и протокол обмена, модель конфликтов, правила обработки повторных запросов, безопасность и восстановление после сбоев.
Почему мобильному приложению недостаточно просто повторять запросы
В обычном онлайн-приложении клиент обращается к серверу, получает актуальные данные, отправляет изменение и ждёт подтверждения. Сервер выступает основной точкой принятия решений, а мобильное приложение преимущественно отображает его состояние.
Когда соединение пропадает, такая модель перестаёт работать. Если каждое действие требует немедленного ответа API, пользователь не сможет полноценно продолжать работу.
Можно автоматически повторять неудачные запросы после восстановления сети. Это полезный механизм, но он решает только проблему доставки. Он не гарантирует, что запрос не выполнится дважды, что данные не устарели и что конкурентные изменения будут обработаны правильно.
Рассмотрим простой пример. Сотрудник заполнил результат технического осмотра и нажал «Сохранить». Сервер выполнил операцию, но соединение оборвалось до получения ответа. Приложение не знает, сохранились данные или нет.
Если оно считает операцию неуспешной и отправляет её заново, возможны два исхода:
сервер повторно применит действие и создаст дубликат;
сервер распознает повтор и вернёт результат первоначальной операции.
Правильное поведение зависит от архитектуры серверной обработки, а не от количества повторных попыток на мобильном устройстве.
Поэтому необходимо различать три события: данные сохранены локально; запрос доставлен и обработан сервером; бизнес-операция подтверждена как успешно завершённая. Эти события не всегда происходят одновременно.
Если приложение не различает состояния операции, оно не сможет надёжно восстановить работу после обрыва связи.
Какую архитектуру использовать для работы офлайн
Для приложений, в которых пользователь должен продолжать работу без постоянного подключения, обычно рассматривают подход offline-first. Его смысл заключается в том, что локальное хранилище становится полноценной частью приложения, а не временным кэшем серверных ответов.
Пользователь читает доступные данные из локальной базы. Изменения сначала фиксируются на устройстве. Синхронизатор передаёт их серверу, когда это становится возможным, и получает обновления, сделанные другими участниками системы.
Схема показывает логические связи, а не обязательную физическую структуру компонентов. Например, локальная база и очередь могут находиться в одном хранилище, а серверный API и обработчик синхронизации — быть частью одного сервиса.
Важен другой принцип: пользовательские действия, локальное хранение и доставка изменений должны быть разделены настолько, чтобы временная недоступность сервера не приводила к потере уже сохранённой работы.
Локальная база данных
В локальной базе хранятся сведения, необходимые для выполнения предусмотренных офлайн-сценариев: задания, карточки объектов, справочники, черновики, результаты проверок и другие рабочие данные.
Для структурированных данных обычно используют встроенную базу данных с поддержкой транзакций. Конкретная технология определяется платформой, объёмом данных, требованиями к запросам и условиями эксплуатации.
Принципиально важно, чтобы локальная база обеспечивала атомарность связанных изменений.
Предположим, пользователь завершает задание. Приложение должно сохранить результат проверки, обновить состояние задания и создать запись для последующей синхронизации. Если приложение аварийно завершится между этими действиями, данные не должны остаться в противоречивом состоянии.
> Поэтому изменение рабочей записи и создание соответствующей операции в очереди следует выполнять в одной локальной транзакции, если они представляют собой единое логическое действие.
Очередь операций
Очередь хранит изменения, которые ещё необходимо передать и согласовать с сервером.
Это могут быть создание документа, изменение полей, добавление комментария, регистрация результата осмотра или завершение задания.
[meta] устойчивый идентификатор;
[meta] связь с конкретным объектом;
[meta] версия исходных данных (основа);
[meta] текущий статус обработки.
Очередь должна переживать перезапуск приложения и временную потерю связи.
> Её нельзя хранить только в оперативной памяти: после аварийного завершения пользователь не должен потерять выполненную работу.
Серверная сторона
Сервер принимает операции, проверяет полномочия пользователя, применяет бизнес-правила и фиксирует результат.
Он также должен распознавать повторные запросы, обнаруживать несовместимые изменения и возвращать клиенту понятный результат обработки.
[action] повторить запрос;
[action] обновить локальные данные;
[action] запросить решение пользователя;
[action] сообщить о невозможности выполнения.
Таким образом, сервер участвует не только в хранении данных, но и в обеспечении их согласованности.
Какие данные необходимо хранить на устройстве
Офлайн-архитектура начинается с определения того, какие данные действительно нужны пользователю без подключения к серверу.
Здесь важно найти баланс. Если хранить слишком мало, приложение не сможет выполнять рабочие сценарии. Если загружать всю корпоративную базу, возрастут требования к памяти, времени синхронизации, защите данных и актуализации справочников.
Для большинства корпоративных приложений полезно разделять локальные данные на несколько категорий.
Особое внимание необходимо уделить различию между локальной копией объекта и изменениями, которые ещё не синхронизированы.
Предположим, приложение загрузило карточку оборудования, после чего сотрудник изменил её статус без подключения к сети. Позднее сервер прислал обновлённую карточку.
Если приложение просто заменит локальную запись серверной, результат работы сотрудника исчезнет.
Следовательно, механизм обновления должен учитывать локальные изменения, которые ещё не получили окончательного результата обработки.
В конкретной реализации это может означать отдельное хранение серверной версии, локального состояния и журнала изменений либо применение другой модели данных, обеспечивающей тот же результат.
Главное требование — обновление серверной копии не должно незаметно уничтожать работу пользователя.
Сквозной пример: технический осмотр без интернета
Рассмотрим условную компанию, которая обслуживает оборудование на удалённых объектах. Сотрудники получают задания в mobile приложении, проверяют оборудование, заполняют результаты осмотра и прикладывают фотографии.
Перед выездом сотрудник открывает задание № 417. Приложение загружает необходимые сведения и сохраняет локальную копию объекта версии 12.
На площадке интернет пропадает. Сотрудник выполняет осмотр, указывает результат «Исправно», добавляет комментарий и фотографию.
Приложение сохраняет результат локально. Пользователь может продолжить работу, но сервер пока не получил новые данные.
В это время диспетчер видит, что оборудование требует дополнительной проверки, и изменяет состояние задания в центральной системе. На сервере появляется версия 13.
Когда интернет восстановится, приложение не должно просто отправить локальную запись и заменить ею серверное состояние. Но и безусловно принять серверное значение недостаточно: результат фактического осмотра может содержать важные сведения.
Система должна обнаружить расхождение и определить, какое правило применимо к этому случаю. Например, если сотрудник и диспетчер изменили независимые поля, изменения можно объединить. Если они установили несовместимые значения одного поля, может потребоваться дополнительная проверка. Если задание было отменено, сервер должен определить, разрешено ли принимать результат позднего осмотра.
Этот пример показывает принципиальную особенность офлайн-систем:
> временное расхождение данных ожидаемо. Проблемой оно становится тогда, когда архитектура не умеет его обнаруживать и корректно разрешать.
Как организовать синхронизацию после восстановления связи
Синхронизация должна решать две задачи: передавать локальные изменения на сервер и получать изменения, которые произошли в центральной системе.
Эти направления нельзя безусловно сводить к операции «скачать всё и заменить локальные данные».
Конкретный порядок зависит от бизнес-процесса. Иногда необходимо сначала передать локальные изменения, в других случаях перед отправкой следует получить актуальное состояние объекта или проверить ограничения.
При этом результат каждой операции должен быть определённым. Клиенту недостаточно знать, что запрос был отправлен: нужно понимать, применено изменение или нет, а если результат неизвестен — безопасно выяснить его.
Инкрементальная синхронизация
Повторная загрузка всех данных при каждом подключении обычно неэффективна. По мере роста объёма локальной базы она увеличивает сетевую нагрузку и время восстановления актуального состояния.
Поэтому часто используют инкрементальную синхронизацию: сервер передаёт изменения, произошедшие после определённой позиции, версии или курсора.
Механизм может основываться на последовательности изменений, версиях записей или журнале событий. Выбор зависит от структуры системы и требований к согласованности.
Важен принцип продвижения курсора.
Предположим, приложение получило очередную порцию изменений, но завершилось до их записи в локальную базу. Если курсор уже обновлён, при следующем запуске система может пропустить эти изменения.
Правильная последовательность должна обеспечивать согласованность между применением данных и фиксацией прогресса синхронизации. Если оба действия невозможно выполнить в одной транзакции, необходимо предусмотреть безопасное восстановление и повторную обработку.
Почему нельзя ориентироваться только на время устройства
Время на мобильном устройстве может быть неточным, изменяться вручную или отличаться от времени на сервере.
Поэтому условие «загрузить все записи, изменённые позже времени последней синхронизации» само по себе не гарантирует полноту обмена.
> Для определения изменений лучше использовать серверные версии, курсоры или другие механизмы, которые обеспечивают однозначное продвижение по журналу изменений.
Временные метки могут быть полезны для аудита и диагностики, но не должны без дополнительных гарантий выступать единственным механизмом согласования данных.
Синхронизация порциями
При большом количестве операций удобно передавать данные пакетами. Это позволяет ограничивать размер запросов, контролировать нагрузку и продолжать обмен после прерывания связи.
Однако необходимо различать пакет передачи и бизнес-трантранзакцию.
Если пять изменений должны применяться только совместно, сервер не должен частично фиксировать их исключительно потому, что они попали в один сетевой пакет. Границы атомарности определяются бизнес-правилами и возможностями серверной обработки.
Очередь операций: как не потерять действие пользователя
Очередь — один из ключевых элементов офлайн-архитектуры. Она позволяет отделить момент выполнения действия от момента его передачи на сервер.
Предположим, пользователь создал документ, добавил несколько строк и завершил его. Приложение должно сохранить не только итоговое представление, но и достаточную информацию для корректного применения операции на сервере.
Для этого каждая операция может содержать:
[op]уникальный идентификатор;
[op]тип действия;
[op]идентификатор объекта;
[op]данные, необходимые для выполнения;
[op]версию, на которой основано изменение;
[op]зависимости от других операций;
[op]статус обработки и сведения о результате.
"operation_id": "op-7f3a91",
"entity_id": "inspection-417",
"operation_type": "complete",
"base_version": 12,
"payload": {
"result": "passed",
"comment": "Проверка выполнена"
},
"status": "pending"
}
Это пример логической структуры, а не обязательный формат API. Реальный состав полей определяется архитектурой приложения.
Почему локальное сохранение и очередь должны быть согласованы
Рассмотрим неправильную последовательность:
Приложение сохраняет результат осмотра. Затем отдельно создаёт операцию в очереди. Между этими действиями приложение аварийно завершается. В результате данные уже присутствуют в локальной базе, но синхронизатор не знает, что их нужно отправить.
Возможна и обратная проблема: операция попала в очередь, но связанные изменения не сохранились полностью.
Правильное решение — фиксировать рабочие изменения и соответствующую запись очереди в одной локальной транзакции, когда они представляют единое логическое действие.
Если транзакция не завершилась, ни одна из связанных частей не должна считаться окончательно сохранённой. Если завершилась — обе доступны для последующей обработки.
Состояния операции
Очередь не должна представлять собой список, из которого запись удаляется сразу после отправки запроса.
Полезно различать состояния «ожидает отправки», «обрабатывается», «подтверждена», «требует разрешения конфликта» и «отклонена». Для некоторых систем нужны также состояния ожидания зависимостей и неопределённого результата.
Это позволяет после перезапуска определить, какие действия можно отправить, какие уже завершены и какие требуют дополнительной проверки.
При этом состояние «отправлено» не эквивалентно состоянию «применено».
> Запрос мог дойти до сервера, но клиент мог не получить подтверждение.
Идемпотентность: как защититься от повторного выполнения
Одна из наиболее сложных проблем синхронизации связана с неопределённым результатом запроса.
Допустим, мобильное приложение отправило команду «Создать документ». Сервер создал документ и зафиксировал транзакцию, но соединение оборвалось до получения ответа. С точки зрения клиента операция выглядит незавершённой. После восстановления связи приложение повторяет запрос. Если сервер воспринимает повтор как новую команду, появляются два документа.
Решение — идемпотентная обработка операций.
Идемпотентность в данном контексте означает, что повторная доставка одной и той же логической операции не приводит к повторному выполнению её бизнес-эффекта. Для этого клиент присваивает операции устойчивый идентификатор, а сервер сохраняет информацию о её обработке. При повторном получении того же идентификатора сервер возвращает ранее зафиксированный результат вместо повторного выполнения действия.
Но одной проверки идентификатора недостаточно. Проверка и выполнение операции должны быть организованы так, чтобы параллельные запросы с одним идентификатором не могли одновременно пройти проверку и создать два бизнес-эффекта.
На практике серверу необходимо согласованно фиксировать результат операции и связанные изменения. В зависимости от архитектуры это обеспечивается транзакциями, ограничениями уникальности и другими средствами защиты от конкурентной обработки.
> Также следует определять, что происходит, если один идентификатор повторно используется с другим содержимым. Такой запрос нельзя автоматически считать безопасным повтором.
Повторная отправка — нормальная часть работы ненадёжной сети. Повторное выполнение уже завершённой операции должно контролироваться сервером.
Конфликты данных: когда два участника изменили одну запись
Пока устройство работает офлайн, другие пользователи могут продолжать менять те же объекты. После восстановления связи локальные изменения необходимо согласовать с актуальным состоянием сервера.
Конфликт возникает не при любом расхождении, а тогда, когда изменения нельзя безопасно применить одновременно по установленным правилам.
Рассмотрим два сценария.
Стратегия 1. Последняя запись побеждает
При подходе last-write-wins система выбирает одно значение согласно определённому правилу порядка.
Это может быть приемлемо для некритичных полей, например для некоторых настроек отображения. Но здесь необходимо учитывать две независимые проблемы.
Поэтому данная стратегия применима только там, где потеря конкурирующего значения допустима и заранее определено, как выбирать победителя.
Стратегия 2. Слияние независимых изменений
Если участники изменили разные поля, система может объединить их изменения.
Однако слияние должно учитывать не только структуру данных, но и бизнес-ограничения. Изменение одного поля может влиять на допустимость другого.
Например, объединить новый комментарий со старой карточкой оборудования обычно проще, чем объединить статус закрытого задания с результатом его повторного выполнения.
> Следовательно, техническая возможность объединить поля ещё не означает, что итоговый объект будет корректным.
Стратегия 3. Оптимистический контроль версий
Один из распространённых подходов — передавать версию объекта, на которой основано изменение.
Предположим, устройство загрузило версию 12. После локального изменения оно отправляет операцию с указанием **base_version = 12**. Но сервер уже хранит версию 13.
Сервер обнаруживает, что операция основана на устаревшей версии, и применяет установленное правило.
Для реализации могут использоваться поле версии, условные обновления, оптимистическая блокировка или эквивалентные механизмы.
Важно, что обнаружение конфликта и его разрешение — разные задачи.
> Проверка версии позволяет заметить потенциальную проблему, но сама по себе не определяет, какое значение должно победить.
Стратегия 4. Журнал событий вместо перезаписи состояния
В некоторых процессах правильнее хранить отдельные факты выполнения, а не перезаписывать один общий статус.
Например, два сотрудника могут независимо провести осмотр одного оборудования. Если каждый результат имеет собственный идентификатор и фиксируется как отдельная запись, система сохраняет оба результата, после чего применяет правила формирования итогового состояния.
Это особенно полезно там, где важна история действий, аудит и возможность объяснить, как было получено текущее состояние объекта.
Однако переход к журналу событий увеличивает сложность архитектуры и не требуется для каждой мобильной системы.
> Его выбирают тогда, когда бизнес-смысл действительно заключается в накоплении событий, а не в хранении одного изменяемого значения.
Удаление записей
Предположим, пользователь удалил объект на устройстве. При следующей синхронизации приложение получает старую серверную копию этого объекта. Если локальное удаление не зафиксировано как самостоятельное изменение, запись может появиться снова.
Для предотвращения этого используют маркеры удаления, часто называемые tombstones, или эквивалентные механизмы фиксации удалённых объектов.
Сведения об удалении необходимо хранить достаточно долго, чтобы их получили все участвующие устройства и процессы.
> Если удалить маркер слишком рано, устройство, которое долго было офлайн, может восстановить уже удалённый объект.
Фотографии и другие вложения
Файлы часто передаются отдельно от основной записи. Это позволяет ограничивать размер запросов, возобновлять загрузку и независимо отслеживать состояние вложений.
Для каждого файла полезно хранить устойчивый идентификатор, размер, контрольную сумму и статус передачи. Конкретный набор метаданных зависит от требований системы.
Если фотография обязательна для закрытия задания, сервер не должен подтверждать окончательное завершение, пока файл не получен и не прошёл необходимые проверки. Если вложение необязательно, его можно передавать отдельно, сохраняя связь с исходным объектом.
Зависимые операции
Допустим, сотрудник офлайн создал документ, добавил к нему строку и завершил обработку.
Сервер может требовать, чтобы создание документа произошло раньше добавления строки, а добавление строки — раньше завершения.
Если отправить все операции параллельно, сервер может получить завершение раньше создания документа или вложение раньше объекта, к которому оно относится.
Поэтому очередь должна учитывать зависимости.
> Независимые операции можно отправлять параллельно, если это безопасно, а зависимые — только после выполнения необходимых предварительных условий.
Какие операции можно выполнять без интернета
Офлайн-доступность должна определяться бизнес-правилами, а не только техническими возможностями приложения.
Возможность сохранить действие локально не означает, что его результат можно считать окончательно подтверждённым.
Например, пользователь может создать заявку на резервирование ресурса без сети. Но подтвердить резервирование система сможет только после проверки актуальной доступности ресурса на сервере, если бизнес-процесс требует глобальной гарантии отсутствия пересечений.
У каждой категории должны быть свои правила интерфейса.
> Если действие сохранено только локально, пользователь не должен воспринимать его как подтверждённую сервером операцию.
Как отображать состояние пользователю
В интерфейсе полезно различать следующие статусы:
[ui] сохранено на устройстве;
[ui] ожидает синхронизации;
[ui] передаётся;
[ui] подтверждено сервером;
[ui] требует разрешения конфликта;
[ui] отклонено;
[ui] результат обработки неизвестен.
Последнее состояние особенно важно. Если сервер мог выполнить операцию, но подтверждение потерялось, нельзя просто объявить её неуспешной.
> Система должна выяснить результат по идентификатору операции или безопасно повторить запрос.
Чёткая индикация состояний уменьшает число повторных действий пользователя и помогает избежать ситуаций, когда одна операция выполняется несколько раз вручную.
Безопасность локальных данных
Офлайн-режим расширяет поверхность риска, поскольку данные теперь находятся не только в центральной инфраструктуре, но и на устройствах сотрудников.
Если телефон потерян, устройство выведено из эксплуатации или доступ пользователя отозван, локальные сведения могут остаться доступными до тех пор, пока не сработают предусмотренные механизмы защиты.
Поэтому необходимо определить, какие данные разрешено хранить на устройстве, как они защищаются и как долго остаются доступными без подключения.
Шифрование и хранение секретов
Следует оценить необходимость шифрования локальной базы и вложений, безопасного хранения ключей и ограничения доступа к файлам.
Токены и другие секреты не следует хранить в обычных файлах приложения без подходящих механизмов защиты.
> Используются средства безопасного хранения, предусмотренные платформой, с учётом модели угроз.
При этом шифрование не отменяет необходимость минимизации данных. Если сотруднику для работы нужны только назначенные ему задания, нет необходимости загружать на устройство весь массив корпоративной информации.
Авторизация без связи
Приложение может разрешать доступ к заранее загруженным данным после временной потери сети. Однако необходимо определить, какие действия доступны без повторной проверки полномочий и как долго сохраняются такие разрешения.
> Есть фундаментальное ограничение: устройство без связи не может немедленно узнать, что сервер отозвал доступ пользователя.
Для чувствительных операций может потребоваться обязательное подключение, ограниченный период офлайн-доступа или дополнительное подтверждение при следующей синхронизации.
Удалённая блокировка
Удалённая команда блокировки или удаления данных не может гарантированно поступить на устройство, которое полностью отключено от сети.
Поэтому нельзя строить безопасность исключительно на возможности удалённого управления. Необходимы защита локального хранилища, ограничение объёма данных, безопасное управление ключами и заранее определённые политики доступа.
Журналирование
Журнал операций помогает выяснять причины конфликтов, повторов и отклонений. Но он не должен бесконтрольно собирать содержимое документов, персональные данные и секреты.
> Нужно заранее определить состав журналируемых событий, доступ к журналам, срок хранения и правила удаления чувствительных сведений.
Как тестировать офлайн-систему
Обычные функциональные тесты при стабильном соединении не позволяют проверить надёжность офлайн-архитектуры.
Необходимо моделировать потерю связи в произвольный момент, повторную доставку запросов, конкурентные изменения, перезапуск приложения и частичное завершение операций.
[case] Связь пропадает до локального сохранения.
[case] Приложение завершается после локального сохранения, но до отправки.
[case] Сервер применяет операцию, а подтверждение теряется.
[case] Один запрос отправляется повторно несколько раз.
[case] Объект изменяется на сервере до синхронизации локальной версии.
[case] Две зависимые операции отправляются в неправильном порядке.
[case] Загрузка вложения прерывается.
[case] Сервер отзывает доступ пользователя во время его отсутствия в сети.
[case] Устройство не подключается несколько дней.
[case] Локальная база не может завершить транзакцию.
[case] Приложение получает новые серверные данные одновременно с локальным изменением объекта.
[case] Несколько устройств одновременно отправляют одну и ту же логическую операцию.
Для каждого сценария нужно определить ожидаемое состояние системы: какие данные должны сохраниться, какие действия разрешено повторять, когда возникает конфликт и что увидит пользователь.
Тестировать нужно не только ошибки, но и восстановление
Предположим, приложение отправило 100 операций. Сервер обработал часть из них, после чего соединение пропало. После восстановления система должна продолжить обмен, не теряя неподтверждённые операции и не создавая повторных бизнес-эффектов.
> Это означает, что тестирование должно охватывать не только факт возникновения сбоя, но и весь последующий путь восстановления.
Какие показатели контролировать после запуска
Для оценки надёжности офлайн-режима полезно отслеживать:
[metric] количество операций, ожидающих синхронизации;
[metric] возраст самой старой необработанной операции;
[metric] долю операций, завершённых без ручного вмешательства;
[metric] частоту конфликтов по типам объектов;
[metric] количество повторных запросов;
[metric] случаи дублирования бизнес-эффектов;
[metric] время от локального сохранения до серверного подтверждения;
[metric] количество операций с неопределённым результатом;
[metric] ошибки передачи вложений;
[metric] потери локальных изменений.
При этом среднее время синхронизации не должно быть единственным показателем качества. Система может быстро передавать большинство операций, но при этом редко терять критичные изменения.
> Для бизнеса такие редкие ошибки могут оказаться гораздо существеннее обычных задержек.
Телеметрию следует собирать с учётом конфиденциальности: для диагностики чаще достаточно идентификаторов, типов операций, версий и кодов ошибок, а не содержимого документов.
Типичные архитектурные ошибки
Даже если локальная база и очередь уже реализованы, отдельные решения могут сделать систему ненадёжной.
[Дефект]: Считать локальное сохранение подтверждением сервера. Создаёт иллюзию готовности, когда данные ещё не доступны другим.
[Дефект]: Безусловно заменять локальные данные серверными. Обновление может полностью уничтожить несинхронизированную работу.
[Дефект]: Повторять запрос без идентификатора операции. Если исходный статус неясен, новый запрос создаст дубликат.
[Дефект]: Считать, что последняя запись всегда правильная. Порядок поступления пакетов не определяет их бизнес-приоритет.
[Дефект]: Не учитывать связи. Приводит к отправке завершения документа раньше создания или передаче вложения без объекта.
[Дефект]: Не проверять длительное отсутствие связи. Локальные данные стареют, права отзываются, объекты отменяются.
[Дефект]: Удалять операцию из очереди сразу после отправки. Сам факт отправки сетевого пакета не гарантирует фиксацию на сервере.
Как выбрать подходящую архитектуру
Не каждому мобильному приложению нужна сложная система синхронизации. Архитектура должна соответствовать последствиям ошибки и характеру бизнес-процесса.
[stage 1] Справочные системы: достаточно локального кэша и планового обновления данных.
[stage 2] Автономный ввод: необходимы локальная база, очередь Outbox, UUID операций и повторы.
[stage 3] Совместная работа: требуются версионный контроль (MVCC) и стратегии разрешения конфликтов.
[stage 4] Критичные операции: обязательны бизнес-инварианты на бэкенде, аудит и разбор неизвестных исходов.
Перед проектированием полезно ответить на следующие вопросы:
[?] Какие действия пользователь должен выполнять без подключения?
[?] Какие данные необходимо заранее загрузить на устройство?
[?] Какие изменения допустимо объединять автоматически?
[?] Какие операции требуют подтверждения актуального состояния сервера?
[?] Как определяется результат запроса, если ответ потерян?
[?] Как восстанавливается синхронизация после частичного сбоя?
[?] Что происходит с локальными данными при отзыве доступа?
[?] Как система обрабатывает устройства, которые долго не выходили в сеть?
Заключение
Работа без постоянного интернета требует от мобильной системы самостоятельности на уровне хранения данных, обработки операций и восстановления после сбоев.
Локальная база позволяет продолжать работу, очередь сохраняет действия для последующей передачи, идемпотентность защищает от повторного выполнения, а версионный контроль помогает обнаруживать несовместимые изменения. Дополнительные правила необходимы для вложений, удаления записей, зависимых операций и защиты локальных данных.
Надёжная система должна не просто отправлять изменения после восстановления связи, но и сохранять возможность объяснить, что произошло с каждой операцией: была ли она принята, повторена, объединена, отклонена или направлена на разрешение конфликта.
Главный принцип офлайн-архитектуры:
временная потеря связи допустима, но потеря уже сохранённой работы, незаметная перезапись изменений и неконтролируемое повторное выполнение бизнес-операций не должны становиться нормальным поведением системы.
API, Webhook или очередь сообщений?
Когда API есть, а интеграция всё равно не работает
Как соединить производство и корпоративные системы
Все инженерные материалы и экспертные статьи
Полный алфавитный справочник ИТ-терминов
🔒 Данные и доступ к системам заказчика обрабатываются в соответствии с согласованными требованиями к безопасности и конфиденциальности. Условия доступа, хранения и обработки данных определяются архитектурой проекта и договором.
Сайт носит исключительно информационный характер и не является публичной офертой в соответствии со статьёй 437 Гражданского кодекса РФ. Цены, состав и условия предоставления услуг уточняются при проектировании решения и фиксируются в договоре. Условия технического сопровождения и уровень сервиса могут дополнительно определяться отдельным соглашением (SLA).
Автоматизация бизнеса и ИИ-решения под ключ
Самозанятый Скопец Антон Викторович ИНН 741709260870