Offline Queue — е механизъм, който запазва потребителските операции локално, когато устройството е офлайн, и ги изпраща към сървъра след възстановяване на връзката. Без офлайн опашка потребителят губи всички действия, извършени без интернет, което е недопустимо в мобилните приложения. Според Google Developers (2025), внедряването на offline-first архитектура повишава задържането на потребители с 30% в региони с нестабилен интернет.
Основни точки
Offline Queue — е подредена колекция от операции (създаване, обновяване, изтриване), която приложението съхранява локално, когато устройството няма достъп до мрежата. След възстановяване на връзката опашката изпраща операциите към сървъра в същия ред, в който потребителят ги е извършил.
Представете си сценарий: потребител на приложение за съобщения пише съобщения в метрото без интернет. Всяко натискане на „Изпращане“ се добавя към Offline Queue. Когато влакът излезе от тунела и мрежата се появи, всички съобщения се изпращат автоматично. Потребителско изживяване — безпроблемно: той не забелязва, че е бил офлайн, освен леко забавяне при изпращане.
Според Uber Engineering (2024), тяхната офлайн опашка обработва над 2 милиона операции на ден в региони с ниско качество на връзката. Опашката използва локално хранилище Room с FIFO ред и механизъм за гарантирана доставка exactly-once.
data class QueuedOperation(
val id: String,
val type: OperationType,
val endpoint: String,
val payload: String,
val timestamp: Long,
val retryCount: Int = 0,
val idempotencyKey: String
)
Всяка операция съдържа всички данни, необходими за повторно изпращане: крайна точка, тяло на заявката, времеви печат и idempotencyKey. Room-БД гарантира запазване на опашката при рестартиране на приложението и сривове на ОС.
Гаранция за доставка — основната задача на опашката. Потребителят трябва да е сигурен, че неговото действие (изпращане на съобщение, харесване, поръчка) ще бъде изпълнено, дори ако мрежата не е налична в момента на изпълнение. Offline Queue с механизъм retry осигурява доставка eventually.
Подобряване на UX при лоша връзка — според GSMA Mobile Economy Report (2025), около 40% от мобилните потребители в света имат нестабилна интернет връзка. Offline Queue прави приложението използваемо в метро, асансьори, отдалечени райони — навсякъде, където връзката е прекъсваща.
Намаляване на загубата на данни — без опашка всички действия, извършени офлайн, се губят. Потребителят може да попълни дълъг формуляр, да натисне „Изпращане“ и да види грешка в мрежата — целият въведен текст се губи. Offline Queue запазва данните и ги изпраща при първа възможност. Auto-save в Google Docs — класически пример за офлайн опашка за документи.
Асинхронна синхронизация — опашката позволява на приложението да не блокира UI по време на изпращане. Потребителят продължава да работи, докато мениджърът за синхронизация обработва опашката на заден план. Това съответства на принципите на Reactive Architecture и подобрява отзивчивостта на интерфейса.
Три слоя на опашката: хранилище (persistence), планировчик (scheduler) и процесор (executor). Хранилище — Room с таблица QueuedOperation. Планировчик — WorkManager (Android) или BGTaskScheduler (iOS), който стартира синхронизация при поява на мрежа. Процесор — последователен итератор FIFO, изпращащ операции една по една.
Ред на обработка — критичен за консистентността на данните. Ако потребителят е създал запис и след това го е редактирал, и двете операции трябва да се изпратят в същия ред. В противен случай сървърът първо ще получи актуализация на несъществуващ запис — грешка. Sequential FIFO — строг ред с контрол на зависимостите между операциите.
Стратегия за сливане — ако в опашката има CREATE и веднага след него DELETE на същия обект, и двете операции могат да бъдат премахнати без изпращане: крайно състояние — обектът не е създаден. По подобен начин, CREATE + UPDATE на същия CREATE могат да се слеят в един CREATE с последните данни. Оптимизация на опашката намалява броя на HTTP заявките и ускорява синхронизацията.
Според Android Developers (2025), WorkManager е предпочитаният начин за обработка на Offline Queue на Android: той гарантира изпълнение дори след рестартиране на устройството, поддържа constraints за наличие на мрежа и позволява задаване на политика за повторни опити чрез NetworkType.CONNECTED.
class SyncWorker(
private val context: Context,
private val params: WorkerParameters
) : CoroutineWorker(context, params) {
override suspend fun doWork(): Result = runCatching {
queueRepository.processNextBatch(batchSize = 10)
Result.success()
}.getOrDefault(Result.retry())
}
CoroutineWorker обработва партиди от операции и връща Result.retry() при неуспех — WorkManager автоматично повтаря стартирането с експоненциално забавяне. Това е най-простият начин да получите надеждна Offline Queue на Android.
Exponential Backoff — стандартна стратегия за повторения с нарастващ интервал: 2 сек, 4 сек, 8 сек, 16 сек и така нататък до максималния праг. Това предотвратява многократното претоварване на сървъра, ако той е временно недостъпен. Java библиотеката Resilience4j (2024) предоставя готова реализация на Retry с конфигурируем backoff.
Максимален брой опити — критичен параметър. Ако след 5–10 опита операцията не е успешна, по-нататъшните повторения са безполезни. Препоръчва се dead letter queue: след изчерпване на опитите операцията се премества в отделна таблица за ръчен анализ. Според Microsoft Patterns & Practices (2024), dead letter queue опростява отстраняването на проблеми със синхронизацията и предотвратява блокирането на опашката от грешни операции.
Jitter — случайна вариация — добавяне на случайно число към интервала на backoff. Ако хиляда устройства едновременно получат мрежа след прекъсване, всички те ще започнат синхронизация едновременно. Jitter ги разпределя във времето, предотвратявайки Cache Stampede на сървъра. Пълен jitter: delay = random(0, backoff) — препоръчан от AWS (2024) за API клиенти.
Last Write Wins (LWW) — най-простата стратегия: при конфликт печели операцията с по-нов времеви печат. LWW изисква синхронизация на времето — времевият печат трябва да се генерира на сървъра или да използва Logical Clock (Lamport clocks). Недостатък: данните на един потребител могат да бъдат презаписани от данни на друг без предупреждение.
OT (Operational Transformation) — алгоритъм, използван от Google Docs и Figma за съвместно редактиране в реално време, включително офлайн режим. OT трансформира операциите, така че да се прилагат към всяко състояние на документа, осигурявайки консистентност без заключвания. CRDT (Conflict-Free Replicated Data Types) — алтернатива на OT, набираща популярност в мобилните приложения: данните са структурирани така, че конфликтите да се разрешават математически без централен сървър.
Custom Merge — за приложения с прост модел на данни (бележки, контакти) могат да се реализират персонализирани правила за сливане. Например за бележка: ако текстът е променен в две версии, да се обединят като конкатенация с разделител. Конфликт, разрешен от потребителя — ако автоматичното сливане е невъзможно, покажете и двете версии на потребителя и предложете да избере. Dropbox (2024) използва този подход за конфликти в офлайн файлове, създавайки копия с префикс „Conflicted Copy“.
Idempotency Key — уникален идентификатор на операция, който сървърът използва за откриване на дублиращи се заявки. Ако клиентът изпрати същата заявка със същия ключ, сървърът връща резултата от вече изпълнената операция, без да я изпълнява повторно. Това е критично важно за Offline Queue, където са възможни повторни изпращания при мрежови грешки.
Формат на idempotency key — UUID или хеш от параметрите на заявката. Сървърът трябва да съхранява изпълнените ключове заедно с резултата за определено време (обикновено 24 часа) за откриване на дубликати. Stripe API (2024) — примерен образец: ключът се предава в заглавката Idempotency-Key и повторните заявки със същия ключ връщат кеширан отговор.
Генериране от клиента — ключът се създава на клиента преди изпращане на операцията и се запазва в таблицата QueuedOperation. При повторен опит ключът не се променя. Exactly-once архитектура — комбинация от idempotency key на клиента и дедупликация на сървъра — единственият начин да се гарантира, че операцията няма да бъде изпълнена два пъти.
fun createOperation(type: OperationType, payload: String): QueuedOperation =
QueuedOperation(
id = UUID.randomUUID().toString(),
type = type,
endpoint = type.endpoint,
payload = payload,
timestamp = currentTimeMillis(),
idempotencyKey = UUID.randomUUID().toString()
)
Всяка операция получава два UUID: един — идентификатор на записа в опашката, вторият — idempotency key за сървъра. Сървърна дедупликация по idempotencyKey гарантира, че дори при повторно изпращане поръчката няма да бъде дублирана.
Често задавани въпроси
Кеш съхранява копия на данни за бързо четене офлайн. Offline Queue съхранява операции на потребителя за последващо записване на сървъра. Кешът работи за четене, опашката — за запис. И двата компонента могат да съществуват съвместно в offline-first архитектура.
Препоръчителен лимит — 100–500 операции. Повече — риск от препълване на паметта и дълга синхронизация при възстановяване на мрежата. При превишаване на лимита приложението трябва да предупреди потребителя и да предложи приоритизиране на операциите. Разумно ограничение — 50 операции за обновяване + 10 за създаване.
Операции по-стари от 7 дни с нулев успех се преместват в dead letter queue. Анализирайте ги ръчно: може би API-то се е променило и крайната точка вече не съществува. Автоматично почистване — HealthCheck задача веднъж на ден изтрива или архивира изтекли операции.
Използвайте граф на зависимостите (DAG): всяка операция съдържа списък от parentOperationId, които трябва да завършат преди нейното изпращане. Room заявка с ORDER BY parent ще върне операциите в правилната последователност. Каскадно изпращане — след завършване на всяка операция проверявайте дали дъщерните операции са отключени.
Използвайте Network Less Tool в Android Emulator или Network Link Conditioner в iOS Simulator за емулация на загуба на мрежа. Пишете тестове, които добавят операции в опашката в офлайн режим, възстановяват връзката и проверяват, че всички операции са изпратени и обработени от сървъра.
Обобщение
Ще разработим мобилно приложение под ключ
IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.
Прочетете също