Offline Queue: principii, strategii și mecanisme de funcționare

Autor: IT Sectr Publicat: 2026-06-13 Timp de citire: 10 min

Offline Queue este un mecanism care salvează operațiile utilizatorului local când dispozitivul este offline și le trimite pe server după restabilirea conexiunii. Fără coada offline, utilizatorul pierde toate acțiunile efectuate fără internet, ceea ce în aplicațiile mobile este inacceptabil. Potrivit Google Developers (2025), implementarea arhitecturii offline-first crește retenția utilizatorilor cu 30% în regiunile cu internet instabil.

Principalele puncte

  • Offline Queue — coadă FIFO de operații pe care utilizatorul le execută fără internet, pentru sincronizare ulterioară.
  • Persistent storage — coada este stocată într-o bază de date locală (SQLite, Room) pentru păstrare la repornirea aplicației.
  • Exponential backoff — strategie de reîncercare cu interval crescător la eșecul trimiterii.
  • Conflict resolution — mecanism de rezolvare a coliziunilor când modificările offline conflictuează cu datele serverului.
  • Idempotency keys — chei unice de operații pentru prevenirea duplicării pe server la retrimitere.

Ce este coada offline?

Offline Queue este o colecție ordonată de operații (creare, actualizare, ștergere) pe care aplicația le salvează local când dispozitivul nu are acces la rețea. De îndată ce conexiunea este restabilită, coada trimite operațiile pe server în aceeași ordine în care utilizatorul le-a efectuat.

Imaginați-vă un scenariu: utilizatorul unui messenger tastează mesaje în metrou fără internet. Fiecare apăsare a butonului „Trimite” este adăugată în Offline Queue. Când trenul iese din tunel și rețeaua apare, toate mesajele sunt trimise automat. Experiența utilizatorului este fluentă: nu observă că a fost offline, în afară de o ușoară întârziere la trimitere.

Potrivit Uber Engineering (2024), coada lor offline procesează peste 2 milioane de operații pe zi în regiuni cu calitate scăzută a conexiunii. Coada utilizează stocarea locală Room cu ordine FIFO și un mecanism de livrare garantată 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
)

Fiecare operație conține toate datele necesare pentru retrimitere: endpoint, corpul cererii, marcaj temporal și idempotencyKey. Baza de date Room garantează păstrarea cozii la repornirea aplicației și la defecțiunile sistemului de operare.

De ce este necesară o coadă de operații în aplicația mobilă

Garantarea livrării este sarcina principală a cozii. Utilizatorul trebuie să fie sigur că acțiunea sa (trimiterea unui mesaj, like, comandă) va fi executată, chiar dacă rețeaua este indisponibilă la momentul executării. Offline Queue cu mecanism de retry asigură livrarea eventuală (eventually).

Îmbunătățirea UX în condiții de conexiune slabă — potrivit GSMA Mobile Economy Report (2025), aproximativ 40% dintre utilizatorii mobili din lume au o conexiune instabilă la internet. Offline Queue face aplicația utilizabilă în metrou, lifturi, zone îndepărtate — oriunde conexiunea este intermitentă.

Reducerea pierderii de date — fără coadă, toate acțiunile efectuate offline se pierd. Utilizatorul poate completa un formular lung, apăsa „Trimite” și vedea o eroare de rețean — toate datele introduse dispar. Offline Queue salvează datele și le trimite la prima ocazie. Salvarea automată în Google Docs este un exemplu clasic de coadă offline pentru documente.

Sincronizarea asincronă — coada permite aplicației să nu blocheze interfața pe durata trimiterii. Utilizatorul continuă să lucreze, iar managerul de sincronizare procesează coada în fundal. Aceasta este conformă cu principiile Arhitecturii Reactive și îmbunătățește receptivitatea interfeței.

Arhitectura cozii offline: stocare și procesare

Trei straturi ale cozii: stocare (persistence), dispecer (scheduler) și procesor (executor). Stocare — Room cu tabelul QueuedOperation. Dispecer — WorkManager (Android) sau BGTaskScheduler (iOS), care pornește sincronizarea la apariția rețelei. Procesor — un iterator secvențial FIFO care trimite operațiile una câte una.

Ordinea de procesare este critică pentru consistența datelor. Dacă utilizatorul a creat o înregistrare și apoi a editat-o, ambele operații trebuie trimise în aceeași ordine. În caz contrar, serverul va primi mai întâi actualizarea unei înregistrări inexistente — eroare. Sequential FIFO — ordine strictă cu controlul dependențelor între operații.

Strategia de îmbinare — dacă în coadă există CREATE și imediat după DELETE al aceluiași obiect, ambele operații pot fi șterse fără trimitere: starea finală — obiectul nu a fost creat. Similar, CREATE + UPDATE CREATE poate fi îmbinat într-un singur CREATE cu cele mai recente date. Optimizarea cozii reduce numărul de cereri HTTP și accelerează sincronizarea.

Potrivit Android Developers (2025), WorkManager este metoda preferată pentru procesarea Offline Queue pe Android: garantează execuția chiar și după repornirea dispozitivului, suportă constrângeri privind disponibilitatea rețelei și permite stabilirea unei politici de reîncercare prin 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 procesează loturile de operații și returnează Result.retry() la eșec — WorkManager reia automat execuția cu o întârziere exponențială. Aceasta este cea mai simplă modalitate de a obține o Offline Queue fiabilă pe Android.

Strategii de reîncercare: exponential backoff și retry policy

Exponential Backoff — strategia standard de reîncercare cu interval crescător: 2 sec, 4 sec, 8 sec, 16 sec și așa mai departe până la un prag maxim. Aceasta previne supraîncărcarea repetată a serverului dacă acesta este temporar indisponibil. Biblioteca Java Resilience4j (2024) oferă o implementare gata preparată Retry cu backoff configurabil.

Numărul maxim de încercări — un parametru critic. Dacă după 5–10 încercări operația nu a reușit, încercările ulterioare sunt inutile. Se recomandă dead letter queue: după epuizarea încercărilor, operația este mutată într-un tabel separat pentru analiză manuală. Potrivit Microsoft Patterns & Practices (2024), dead letter queue simplifică depanarea problemelor de sincronizare și previne blocarea cozii de către operații eronate.

Jitter — variație aleatoare — adăugarea unui număr aleator la intervalul backoff. Dacă o mie de dispozitive și-au restabilit simultan conexiunea după o deconectare, toate vor începe sincronizarea în același timp. Jitter le distribuie în timp, prevenind Cache Stampede pe server. Jitter complet: delay = random(0, backoff) — recomandat de AWS (2024) pentru clienții API.

Rezolvarea conflictelor: cum să gestionăm coliziunile de date

Last Write Wins (LWW) — cea mai simplă strategie: la conflict, câștigă operația cu marcajul temporal mai recent. LWW necesită sincronizarea timpului — timestamp trebuie generat pe server sau să utilizeze Logical Clock (ceasuri Lamport). Dezavantaj: datele unui utilizator pot fi suprascrise de datele altuia fără avertisment.

OT (Operational Transformation) — algoritm utilizat de Google Docs și Figma pentru editare colaborativă în timp real, inclusiv în modul offline. OT transformă operațiile astfel încât să se aplice oricărei stări a documentului, asigurând consistența fără blocaje. CRDT (Conflict-Free Replicated Data Types) — alternativă la OT, care câștigă popularitate în aplicațiile mobile: datele sunt structurate astfel încât conflictele să fie rezolvabile matematic, fără un server central.

Îmbinare personalizată — pentru aplicații cu un model simplu de date (note, contacte) se pot implementa reguli personalizate de îmbinare. De exemplu, pentru o notă: dacă textul a fost modificat în două versiuni, împreună-le ca o concatenare cu un separator. Conflict rezolvat de utilizator — dacă îmbinarea automată nu este posibilă, afișați utilizatorului ambele versiuni și propuneți alegerea. Dropbox (2024) utilizează această abordare pentru conflictele în fișiere offline, creând copii cu prefixul „Conflicted Copy”.

Idempotency keys — protecție împotriva duplicării

Idempotency Key — un identificator unic al operației pe care serverul îl utilizează pentru detectarea cererilor duplicate. Dacă clientul trimite aceeași cerere cu aceeași cheie, serverul returnează rezultatul operației deja executate, fără a o executa din nou. Acest lucru este critic pentru Offline Queue, unde retrimiterile sunt posibile în cazul erorilor de rețean.

Formatul idempotency key — UUID sau hash al parametrilor cererii. Serverul trebuie să stocheze cheile executate împreună cu rezultatul pentru o perioadă de timp (de obicei 24 de ore) pentru detectarea duplicatelor. Stripe API (2024) — un exemplu de referință: cheia este transmisă în antetul Idempotency-Key, iar cererile repetate cu aceeași cheie returnează răspunsul stocat în cache.

Generarea pe partea clientului — cheia este creată pe client înainte de trimiterea operației și salvată în tabelul QueuedOperation. La reîncercare, cheia nu se schimbă. Arhitectura exactly-once — combinația dintre idempotency key pe client și deduplicarea pe server — singura modalitate de a garanta că operația nu va fi executată de două ori.

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

Fiecare operație primește două UUID-uri: unul — identificatorul înregistrării în coadă, al doilea — idempotency key pentru server. Deduplicarea pe partea serverului după idempotencyKey garantează că, chiar și la retrimitere, comanda nu va fi duplicată.

Întrebări frecvente

Cu ce se deosebește Offline Queue de cache?

Cache-ul stochează copii ale datelor pentru citire rapidă offline. Offline Queue stochează operațiile utilizatorului pentru scrierea ulterioară pe server. Cache-ul funcționează pentru citire, coada — pentru scriere. Ambele componente pot coexista într-o arhitectură offline-first.

Ce dimensiune a cozii este sigură pentru un dispozitiv mobil?

Limita recomandată — 100–500 de operații. Mai mult — risc de depășire a memoriei și sincronizare lungă la restabilirea rețelei. La depășirea limitei, aplicația trebuie să avertizeze utilizatorul și să propună prioritizarea operațiilor. Limită rezonabilă — 50 de operații de actualizare + 10 de creare.

Cum să gestionăm operațiile învechite din coadă?

Operațiile mai vechi de 7 zile cu succes zero sunt mutate în dead letter queue. Analizați-le manual: poate că API-ul s-a schimbat și endpoint-ul nu mai există. Curățarea automată — o sarcină HealthCheck o dată pe zi șterge sau arhivează operațiile expirate.

Ce facem dacă o operație depinde de una anterioară care nu a fost încă trimisă?

Utilizați un graf de dependențe (DAG): fiecare operație conține o listă de parentOperationId care trebuie finalizate înainte de trimiterea ei. Interogarea Room cu ORDER BY parent va returna operațiile în ordinea corectă. Trimitere în cascadă — după finalizarea fiecărei operații, verificați dacă operațiile copil au fost deblocate.

Cum testăm Offline Queue?

Utilizați Network Less Tool în Android Emulator sau Network Link Conditioner în iOS Simulator pentru a emula pierderea rețelei. Scrieți teste care adaugă operații în coadă în modul offline, restaurează conexiunea și verifică dacă toate operațiile au fost trimise și procesate de server.

Concluzii

  • Offline Queue — coadă FIFO de operații stocată local pentru trimitere după restabilirea conexiunii.
  • Persistent storage (Room / SQLite) — obligatoriu pentru păstrarea cozii la repornirea aplicației.
  • Exponential backoff cu jitter — strategia standard de reîncercare pentru prevenirea supraîncărcării serverului.
  • Conflict resolution — LWW, OT, CRDT sau reguli personalizate pentru rezolvarea coliziunilor datelor offline.
  • Idempotency key — UUID al fiecărei operații pentru asigurarea livrării exactly-once pe server.
  • Dead letter queue — izolarea operațiilor problematice după epuizarea încercărilor pentru analiză manuală.
  • Cea mai bună practică pentru Android — WorkManager + Room + ExponentialBackoff — combinație testată de Google.

Vom dezvolta o aplicație mobilă la cheie

IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.

Discutați proiectul

Citiți și