Offline Queue: zasady, strategie i mechanizmy działania

Autor: IT Sectr Opublikowano: 2026-06-13 Czas czytania: 10 min

Offline Queue to mechanizm, który zapisuje operacje użytkownika lokalnie, gdy urządzenie jest poza siecią, i wysyła je na serwer po przywróceniu połączenia. Bez kolejki offline użytkownik traci wszystkie działania wykonane bez internetu, co w aplikacjach mobilnych jest niedopuszczalne. Według Google Developers (2025), wdrożenie architektury offline-first zwiększa retencję użytkowników o 30% w regionach z niestabilnym internetem.

Najważniejsze

  • Offline Queue — kolejka FIFO operacji wykonywanych przez użytkownika bez internetu, do późniejszej synchronizacji.
  • Persistent storage — kolejka przechowywana w lokalnej bazie danych (SQLite, Room) dla zachowania przy ponownym uruchomieniu aplikacji.
  • Exponential backoff — strategia ponawiania prób z rosnącym odstępem czasu przy niepowodzeniu wysyłki.
  • Conflict resolution — mechanizm rozwiązywania kolizji, gdy zmiany offline kolidują z danymi serwerowymi.
  • Idempotency keys — unikalne klucze operacji zapobiegające duplikacji na serwerze przy ponownej wysyłce.

Czym jest kolejka offline?

Offline Queue to uporządkowana kolekcja operacji (tworzenie, aktualizacja, usuwanie), które aplikacja zapisuje lokalnie, gdy urządzenie nie ma dostępu do sieci. Gdy połączenie zostanie przywrócone, kolejka wysyła operacje na serwer w tej samej kolejności, w jakiej użytkownik je wykonał.

Wyobraź sobie scenariusz: użytkownik komunikatora pisze wiadomości w metrze bez internetu. Każde naciśnięcie «Wyślij» jest dodawane do Offline Queue. Gdy pociąg wyjeżdża z tunelu i pojawia się sieć, wszystkie wiadomości są wysyłane automatycznie. Doświadczenie użytkownika jest płynne: nie zauważa on, że był offline, poza lekkim opóźnieniem przy wysyłaniu.

Według Uber Engineering (2024), ich kolejka offline przetwarza ponad 2 miliony operacji dziennie w regionach o niskiej jakości połączenia. Kolejka wykorzystuje lokalne przechowywanie Room z kolejnością FIFO i mechanizmem gwarantowanej dostawy exactly-once.

kotlin
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
)

Każda operacja zawiera wszystkie dane niezbędne do ponownego wysłania: endpoint, treść żądania, znacznik czasu i idempotencyKey. Baza Room gwarantuje zachowanie kolejki przy ponownym uruchomieniu aplikacji i awariach systemu.

Po co kolejka operacji w aplikacji mobilnej

Gwarancja dostarczenia to główne zadanie kolejki. Użytkownik musi być pewien, że jego działanie (wysłanie wiadomości, polubienie, zamówienie) zostanie wykonane, nawet jeśli sieć jest niedostępna w momencie wykonania. Offline Queue z mechanizmem retry zapewnia dostarczenie docelowe (eventually).

Poprawa UX w warunkach słabego połączenia — według GSMA Mobile Economy Report (2025), około 40% użytkowników mobilnych na świecie ma niestabilne połączenie internetowe. Offline Queue sprawia, że aplikacja nadaje się do użytku w metrze, windach, odległych obszarach — wszędzie, gdzie połączenie jest przerywane.

Zmniejszenie utraty danych — bez kolejki wszystkie działania wykonane offline są tracone. Użytkownik może wypełnić długi formularz, nacisnąć «Wyślij» i zobaczyć błąd sieci — cały wpis przepada. Offline Queue zapisuje dane i wysyła je przy pierwszej okazji. Auto-zapis w Google Docs to klasyczny przykład kolejki offline dla dokumentów.

Asynchroniczna synchronizacja — kolejka pozwala aplikacji nie blokować interfejsu na czas wysyłania. Użytkownik kontynuuje pracę, a menedżer synchronizacji przetwarza kolejkę w tle. Jest to zgodne z zasadami Architektury Reaktywnej i poprawia responsywność interfejsu.

Architektura kolejki offline: przechowywanie i przetwarzanie

Trzy warstwy kolejki: przechowywanie (persistence), dyspozytor (scheduler) i procesor (executor). Przechowywanie — Room z tabelą QueuedOperation. Dyspozytor — WorkManager (Android) lub BGTaskScheduler (iOS), który uruchamia synchronizację przy pojawieniu się sieci. Procesor — sekwencyjny iterator FIFO wysyłający operacje pojedynczo.

Kolejność przetwarzania jest krytyczna dla spójności danych. Jeśli użytkownik utworzył rekord, a następnie go edytował, obie operacje muszą zostać wysłane w tej samej kolejności. W przeciwnym razie serwer najpierw otrzyma aktualizację nieistniejącego rekordu — błąd. Sequential FIFO — ścisła kolejność z kontrolą zależności między operacjami.

Strategia łączenia — jeśli w kolejce są CREATE i zaraz po nim DELETE tego samego obiektu, można usunąć obie operacje bez wysyłania: stan końcowy — obiekt nie został utworzony. Podobnie CREATE + UPDATE CREATE można połączyć w jeden CREATE z najnowszymi danymi. Optymalizacja kolejki zmniejsza liczbę zapytań HTTP i przyspiesza synchronizację.

Według Android Developers (2025), WorkManager to preferowany sposób obsługi Offline Queue na Androidzie: gwarantuje wykonanie nawet po restarcie urządzenia, obsługuje ograniczenia dotyczące dostępności sieci i umożliwia ustawienie polityki ponawiania poprzez NetworkType.CONNECTED.

kotlin
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 przetwarza partie operacji i zwraca Result.retry() przy niepowodzeniu — WorkManager automatycznie ponawia uruchomienie z wykładniczym opóźnieniem. To najprostszy sposób uzyskania niezawodnej Offline Queue na Androidzie.

Strategie ponawiania: exponential backoff i retry policy

Exponential Backoff — standardowa strategia powtórzeń ze zwiększającym się odstępem: 2 sek, 4 sek, 8 sek, 16 sek i tak dalej aż do maksymalnego progu. Zapobiega to przeciążeniu serwera przy czasowej niedostępności. Biblioteka Java Resilience4j (2024) dostarcza gotową implementację Retry z konfigurowalnym backoffem.

Maksymalna liczba prób — parametr krytyczny. Jeśli po 5–10 próbach operacja się nie powiodła, dalsze próby są bezużyteczne. Zaleca się dead letter queue: po wyczerpaniu prób operacja jest przenoszona do osobnej tabeli do ręcznej analizy. Według Microsoft Patterns & Practices (2024), dead letter queue upraszcza debugowanie problemów synchronizacji i zapobiega blokowaniu kolejki przez błędne operacje.

Jitter — losowa wariancja — dodanie losowej liczby do odstępu backoff. Jeśli tysiąc urządzeń jednocześnie odzyskało sieć po rozłączeniu, wszystkie rozpoczną synchronizację w tym samym momencie. Jitter rozkłada je w czasie, zapobiegając Cache Stampede na serwerze. Pełny jitter: delay = random(0, backoff) — zalecany przez AWS (2024) dla klientów API.

Rozwiązywanie konfliktów: jak radzić sobie z kolizjami danych

Last Write Wins (LWW) — najprostsza strategia: w przypadku konfliktu wygrywa operacja z późniejszym znacznikiem czasu. LWW wymaga synchronizacji czasu — timestamp musi być generowany na serwerze lub używać Logical Clock (zegary Lamporta). Minus: dane jednego użytkownika mogą zostać nadpisane danymi innego bez ostrzeżenia.

OT (Operational Transformation) — algorytm używany przez Google Docs i Figma do wspólnego edytowania w czasie rzeczywistym, w tym w trybie offline. OT przekształca operacje tak, aby stosowały się do dowolnego stanu dokumentu, zapewniając spójność bez blokad. CRDT (Conflict-Free Replicated Data Types) — alternatywa dla OT, zyskująca popularność w aplikacjach mobilnych: dane są strukturyzowane tak, że konflikty są rozwiązywalne matematycznie, bez centralnego serwera.

Niestandardowe łączenie — dla aplikacji z prostym modelem danych (notatki, kontakty) można zaimplementować własne reguły łączenia. Na przykład dla notatki: jeśli tekst został zmieniony w dwóch wersjach, połącz je jako konkatenację z separatorem. Konflikt rozwiązywany przez użytkownika — jeśli automatyczne łączenie jest niemożliwych, pokaż użytkownikowi obie wersje i zaproponuj wybór. Dropbox (2024) stosuje takie podejście dla konfliktów w plikach offline, tworząc kopie z prefiksem «Conflicted Copy».

Idempotency keys — ochrona przed duplikowaniem

Idempotency Key — unikalny identyfikator operacji, który serwer wykorzystuje do wykrywania duplikujących się żądań. Jeśli klient wysyła to samo żądanie z tym samym kluczem, serwer zwraca wynik już wykonanej operacji, nie wykonując jej ponownie. Jest to krytyczne dla Offline Queue, gdzie możliwe są wielokrotne wysyłki przy błędach sieciowych.

Format idempotency key — UUID lub hash parametrów żądania. Serwer musi przechowywać wykonane klucze wraz z wynikiem przez pewien czas (zwykle 24 godziny) w celu wykrywania duplikatów. Stripe API (2024) — przykład wzorcowy: klucz jest przekazywany w nagłówku Idempotency-Key, a powtórne żądania z tym samym kluczem zwracają zapisaną odpowiedź.

Generowanie po stronie klienta — klucz jest tworzony na kliencie przed wysłaniem operacji i zapisywany w tabeli QueuedOperation. Przy ponownej próbie klucz się nie zmienia. Architektura exactly-once — kombinacja idempotency key na kliencie i deduplikacji na serwerze — jedyny sposób zagwarantowania, że operacja nie zostanie wykonana dwukrotnie.

kotlin
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()
    )

Każda operacja otrzymuje dwa UUID: jeden — identyfikator rekordu w kolejce, drugi — idempotency key dla serwera. Deduplikacja po stronie serwera według idempotencyKey gwarantuje, że nawet przy ponownym wysłaniu zamówienie nie zostanie zdublowane.

Często zadawane pytania

Czym Offline Queue różni się od pamięci podręcznej (cache)?

Pamięć podręczna (cache) przechowuje kopie danych do szybkiego odczytu offline. Offline Queue przechowuje operacje użytkownika do późniejszego zapisu na serwer. Cache działa na odczyt, kolejka — na zapis. Oba komponenty mogą współistnieć w architekturze offline-first.

Jaki rozmiar kolejki jest bezpieczny dla urządzenia mobilnego?

Zalecany limit — 100–500 operacji. Więcej — ryzyko przepełnienia pamięci i długiej synchronizacji po przywróceniu sieci. Po przekroczeniu limitu aplikacja powinna ostrzec użytkownika i zaproponować priorytetyzację operacji. Rozsądne ograniczenie — 50 operacji aktualizacji + 10 tworzenia.

Jak obsługiwać przestarzałe operacje w kolejce?

Operacje starsze niż 7 dni z zerowym sukcesem są przenoszone do dead letter queue. Analizuj je ręcznie: być może API się zmieniło i endpoint już nie istnieje. Automatyczne czyszczenie — zadanie HealthCheck raz na dobę usuwa lub archiwizuje przeterminowane operacje.

Co zrobić, gdy operacja zależy od poprzedniej, która nie została jeszcze wysłana?

Użyj grafu zależności (DAG): każda operacja zawiera listę parentOperationId, które muszą zostać zakończone przed jej wysłaniem. Zapytanie Room z ORDER BY parent zwróci operacje we właściwej kolejności. Wysyłanie kaskadowe — po zakończeniu każdej operacji sprawdzaj, czy nie zostały odblokowane zależne.

Jak testować Offline Queue?

Użyj Network Less Tool w Android Emulator lub Network Link Conditioner w iOS Simulator do emulacji utraty sieci. Pisz testy, które dodają operacje do kolejki w trybie offline, przywracają połączenie i sprawdzają, czy wszystkie operacje zostały wysłane i przetworzone przez serwer.

Podsumowanie

  • Offline Queue — kolejka FIFO operacji przechowywana lokalnie do wysyłania po przywróceniu połączenia.
  • Persistent storage (Room / SQLite) — niezbędny do zachowania kolejki przy restarcie aplikacji.
  • Exponential backoff z jitterem — standardowa strategia powtórzeń zapobiegająca przeciążeniu serwera.
  • Conflict resolution — LWW, OT, CRDT lub własne reguły rozwiązywania kolizji danych offline.
  • Idempotency key — UUID każdej operacji zapewniający dostawę exactly-once na serwerze.
  • Dead letter queue — izolacja problematycznych operacji po wyczerpaniu prób do ręcznej analizy.
  • Najlepsza praktyka dla Androida — WorkManager + Room + ExponentialBackoff — sprawdzona kombinacja od Google.

Opracujemy aplikację mobilną pod klucz

IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.

Omów projekt

Przeczytaj również