Offline Queue: principer, strategier och funktionsmekanismer

Författare: IT Sectr Publicerad: 2026-06-13 Lästid: 10 min

Offline Queue — är en mekanism som sparar användaroperationer lokalt när enheten är offline och skickar dem till servern när anslutningen återställs. Utan en offlinekö förlorar användaren alla åtgärder som utförts utan internet, vilket är oacceptabelt i mobilapplikationer. Enligt Google Developers (2025) ökar implementeringen av offline-first-arkitektur användarbehållningen med 30% i regioner med instabilt internet.

Huvudpunkter

  • Offline Queue — FIFO-kö för operationer som användaren utför utan internet, för efterföljande synkronisering.
  • Persistent storage — kön lagras i lokal DB (SQLite, Room) för att bevaras vid omstart av applikationen.
  • Exponential backoff — strategi för återförsök med ökande intervall vid misslyckad sändning.
  • Conflict resolution — mekanism för att lösa konflikter när offlineändringar kolliderar med serverdata.
  • Idempotency keys — unika operationsnycklar för att förhindra dubbellagring på servern vid återsändning.

Vad är en offlinekö?

Offline Queue — är en ordnad samling operationer (skapa, uppdatera, ta bort) som applikationen lagrar lokalt när enheten inte har nätverksåtkomst. När anslutningen återställs skickar kön operationerna till servern i samma ordning som användaren utförde dem.

Föreställ dig ett scenario: en användare av en meddelandeapp skriver meddelanden i tunnelbanan utan internet. Varje tryck på “Skicka” läggs till i Offline Queue. När tåget kommer ut ur tunneln och nätverket visas skickas alla meddelanden automatiskt. Användarupplevelsen — sömlös: användaren märker inte att den var offline, förutom en liten fördröjning vid sändning.

Enligt Uber Engineering (2024) bearbetar deras offlinekö över 2 miljoner operationer per dag i regioner med låg anslutningskvalitet. Kön använder lokal Room-lagring med FIFO-ordning och en mekanism för garanterad leverans 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
)

Varje operation innehåller all data som behövs för återsändning: endpoint, förfrågans brödtext, tidsstämpel och idempotencyKey. Room-DB garanterar att kön bevaras vid applikationsomstart och OS-fel.

Varför behövs en operationskö i en mobilapp

Leveransgaranti — könens huvuduppgift. Användaren måste vara säker på att dess åtgärd (skicka meddelande, gilla, beställa) kommer att utföras, även om nätverket inte är tillgängligt vid utförandetillfället. Offline Queue med retry-mekanism säkerställer leverans eventually.

Förbättrad UX vid dålig anslutning — enligt GSMA Mobile Economy Report (2025) har cirka 40% av mobilanvändarna i världen instabil internetanslutning. Offline Queue gör appen användbar i tunnelbanor, hissar, avlägsna områden — överallt där anslutningen är intermittent.

Minskad dataförlust — utan kö förloras alla åtgärder som utförs offline. Användaren kan fylla i ett långt formulär, trycka på “Skicka” och se ett nätverksfel — all inmatning går förlorad. Offline Queue sparar data och skickar dem vid första tillfället. Auto-save i Google Docs — ett klassiskt exempel på offlinekö för dokument.

Asynkron synkronisering — kön gör att applikationen inte blockerar UI:t under sändning. Användaren fortsätter att arbeta medan synkroniseringshanteraren bearbetar kön i bakgrunden. Detta överensstämmer med principerna för Reactive Architecture och förbättrar gränssnittets responsivitet.

Arkitektur för offlinekö: lagring och bearbetning

Tre lager av kön: lagring (persistence), schemaläggare (scheduler) och processor (executor). Lagring — Room med tabell QueuedOperation. Schemaläggare — WorkManager (Android) eller BGTaskScheduler (iOS), som startar synkronisering när nätverk blir tillgängligt. Processor — sekventiell FIFO-iterator som skickar operationer en i taget.

Bearbetningsordning — kritisk för datakonsistens. Om användaren skapade en post och sedan redigerade den, måste båda operationerna skickas i samma ordning. Annars får servern först en uppdatering av en post som inte existerar — fel. Sequential FIFO — strikt ordning med beroendekontroll mellan operationer.

Sammanslagningsstrategi — om det finns en CREATE och omedelbart därefter en DELETE av samma objekt i kön, kan båda operationerna tas bort utan sändning: slutligt tillstånd — objektet skapades inte. På samma sätt kan CREATE + UPDATE av samma CREATE slås samman till en CREATE med de senaste uppgifterna. Köoptimering minskar antalet HTTP-förfrågningar och påskyndar synkronisering.

Enligt Android Developers (2025) är WorkManager det föredragna sättet att hantera Offline Queue på Android: det garanterar exekvering även efter enhetsomstart, stöder begränsningar för nätverkstillgänglighet och tillåter inställning av återförsökspolicy via 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 bearbetar batchar av operationer och returnerar Result.retry() vid fel — WorkManager återupprepar automatiskt starten med exponentiell fördröjning. Detta är det enklaste sättet att få en pålitlig Offline Queue på Android.

Strategier för återförsök: exponential backoff och retry-policy

Exponential Backoff — standardstrategi för återförsök med ökande intervall: 2 s, 4 s, 8 s, 16 s och så vidare upp till maxgränsen. Detta förhindrar upprepad överbelastning av servern om den är tillfälligt otillgänglig. Java-biblioteket Resilience4j (2024) tillhandahåller en färdig Retry-implementation med konfigurerbar backoff.

Maximalt antal försök — en kritisk parameter. Om operationen misslyckats efter 5–10 försök är ytterligare försök meningslösa. Rekommenderas är dead letter queue: efter att försöken är slut flyttas operationen till en separat tabell för manuell analys. Enligt Microsoft Patterns & Practices (2024) förenklar dead letter queue felsökning av synkroniseringsproblem och förhindrar att kön blockeras av felaktiga operationer.

Jitter — slumpmässig variation — tillägg av ett slumpmässigt tal till backoff-intervallet. Om tusen enheter samtidigt får nätverk efter en frånkoppling kommer de alla att starta synkronisering samtidigt. Jitter sprider ut dem i tid och förhindrar Cache Stampede på servern. Fullständig jitter: delay = random(0, backoff) — rekommenderas av AWS (2024) för API-klienter.

Konfliktlösning: hur man löser datakonflikter

Last Write Wins (LWW) — den enklaste strategin: vid konflikt vinner operationen med den senare tidsstämpeln. LWW kräver tidssynkronisering — tidsstämpeln måste genereras på servern eller använda Logical Clock (Lamport clocks). Nackdel: en användares data kan skrivas över av en annan användares data utan varning.

OT (Operational Transformation) — algoritm som används av Google Docs och Figma för samarbetsredigering i realtid, inklusive offlineläge. OT omvandlar operationer så att de kan tillämpas på vilket dokumenttillstånd som helst, vilket säkerställer konsistens utan låsning. CRDT (Conflict-Free Replicated Data Types) — ett alternativ till OT som blir populärt i mobilappar: data är strukturerade så att konflikter kan lösas matematiskt utan central server.

Custom Merge — för applikationer med enkel datamodell (anteckningar, kontakter) kan anpassade sammanslagningsregler implementeras. Till exempel för en anteckning: om texten ändrats i två versioner, slå samman dem som en konkatenering med avgränsare. Användarlöst konflikt — om automatisk sammanslagning inte är möjlig, visa båda versionerna för användaren och låt dem välja. Dropbox (2024) använder detta tillvägagångssätt för konflikter i offlinefiler och skapar kopior med prefix “Conflicted Copy”.

Idempotency keys — skydd mot dubbellagring

Idempotency Key — unik identifierare för en operation som servern använder för att upptäcka dubblerade förfrågningar. Om klienten skickar samma förfrågan med samma nyckel returnerar servern resultatet av den redan utförda operationen utan att utföra den igen. Detta är kritiskt för Offline Queue där återsändningar är möjliga vid nätverksfel.

Format för idempotency key — UUID eller hash av förfrågeparametrar. Servern måste lagra utförda nycklar tillsammans med resultatet under en viss tid (vanligtvis 24 timmar) för att upptäcka dubbletter. Stripe API (2024) — ett exemplariskt exempel: nyckeln skickas i rubriken Idempotency-Key och upprepade förfrågningar med samma nyckel returnerar cachat svar.

Klientgenerering — nyckeln skapas på klienten innan operationen skickas och sparas i tabellen QueuedOperation. Vid återförsök ändras inte nyckeln. Exactly-once-arkitektur — kombinationen av idempotency key på klienten och deduplicering på servern — det enda sättet att garantera att en operation inte utförs två gånger.

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

Varje operation får två UUID: ett — identifierare för posten i kön, det andra — idempotency key för servern. Serverdeduplicering baserat på idempotencyKey garanterar att även vid återsändning inte beställningen dupliceras.

Vanliga frågor

Hur skiljer sig Offline Queue från cache?

Cache lagrar datakopior för snabb läsning offline. Offline Queue lagrar användaroperationer för efterföljande skrivning till servern. Cache fungerar för läsning, kön — för skrivning. Båda komponenterna kan samexistera i offline-first-arkitektur.

Vilken köstorlek är säker för en mobil enhet?

Rekommenderad gräns — 100–500 operationer. Fler — risk för minnesöversvämning och lång synkronisering vid återställning av nätverk. Vid överskridande av gränsen bör applikationen varna användaren och föreslå prioritering av operationer. Förnuftig begränsning — 50 uppdateringsoperationer + 10 skapandeoperationer.

Hur hanterar man föråldrade operationer i kön?

Operationer äldre än 7 dagar med noll framgång flyttas till dead letter queue. Analysera dem manuellt: kanske har API ändrats och slutpunkten finns inte längre. Automatisk rensning — HealthCheck-uppgift en gång om dagen tar bort eller arkiverar utgångna operationer.

Vad gör man om en operation är beroende av en tidigare som ännu inte skickats?

Använd beroendegraf (DAG): varje operation innehåller en lista med parentOperationId som måste slutföras innan den skickas. Room-fråga med ORDER BY parent returnerar operationer i rätt ordning. Kaskadsändning — efter att varje operation slutförts, kontrollera om underordnade operationer har låsts upp.

Hur testar man Offline Queue?

Använd Network Less Tool i Android Emulator eller Network Link Conditioner i iOS Simulator för att simulera nätverksförlust. Skriv tester som lägger till operationer i kön i offlineläge, återställer anslutningen och kontrollerar att alla operationer har skickats och bearbetats av servern.

Sammanfattning

  • Offline Queue — FIFO-kö för operationer som lagras lokalt för sändning efter återställd anslutning.
  • Persistent storage (Room / SQLite) — nödvändig för att bevara kön vid applikationsomstart.
  • Exponential backoff med jitter — standardstrategi för återförsök för att förhindra serveröverbelastning.
  • Conflict resolution — LWW, OT, CRDT eller anpassade regler för att lösa offline-datakonflikter.
  • Idempotency key — UUID för varje operation för att säkerställa exactly-once-leverans på servern.
  • Dead letter queue — isolering av problematiska operationer efter att försöken är slut för manuell analys.
  • Bästa praxis för Android — WorkManager + Room + ExponentialBackoff — beprövad kombination från Google.

Vi utvecklar en mobil applikation nyckelfärdigt

IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.

Diskutera projektet

Läs också