Offline-Modus und Caching verstehen

Wie LobbyFlight mit Verbindungsunterbrechungen umgeht und Daten intelligent zwischenspeichert

15 min readLast updated: 1/15/20240

Offline-Modus und Caching verstehen

LobbyFlight ist für 24/7-Betrieb ausgelegt und kann Netzwerkunterbrechungen intelligent handhaben. Diese Anleitung erklärt die mehrstufige Caching-Architektur und Offline-Funktionalität.

Service Worker Architektur

Das Herzstück der Offline-Funktionalität ist der Service Worker - ein JavaScript-Prozess, der zwischen Browser und Netzwerk vermittelt.

Die drei Cache-Ebenen

LobbyFlight verwendet drei spezialisierte Cache-Speicher:

1. CACHE_NAME (lobbyflight-v1)

Zweck: Speichert essenzielle App-Ressourcen

Inhalt:

  • Haupt-HTML-Seite
  • CSS-Stylesheets
  • JavaScript-Bundles
  • Schriftarten
  • Logo und Icons
  • Lebensdauer: Bis zum nächsten App-Update

    2. RUNTIME_CACHE

    Zweck: Dynamisch generierte Inhalte

    Inhalt:

  • Gerenderte Seiten
  • Dynamische Assets
  • Benutzer-spezifische Inhalte
  • Lebensdauer: Automatisches Cleanup bei Update

    3. API_CACHE

    Zweck: API-Responses mit Zeitstempel

    Inhalt:

  • Flight-Data Responses
  • Weather-Data Responses
  • Configuration Responses
  • Besonderheit: Jeder Cache-Eintrag erhält Zeitstempel für Aktualitätsprüfung

    Caching-Strategien im Detail

    API-Requests: Network-First, Cache-Fallback

    Ablauf:

  • Versuch, Daten vom Server zu holen
  • Bei Erfolg: Response cachen und anzeigen
  • Bei Fehler: Gecachte Daten verwenden
  • Kein Cache vorhanden: Offline-Meldung
  • Code-Beispiel:

    // Vereinfachte Darstellung
    fetch(apiRequest)
      .then(response => {
        cache.put(apiRequest, response.clone())
        return response
      })
      .catch(() => {
        return cache.match(apiRequest) || offlineFallback
      })

    Vorteile:

  • Immer aktuelle Daten wenn online
  • Graceful Degradation bei Offline
  • Keine veralteten Daten bei guter Verbindung
  • Static Assets: Cache-First, Network-Fallback

    Ablauf:

  • Prüfung ob Asset im Cache
  • Wenn ja: Sofort aus Cache laden (schnell!)
  • Wenn nein: Vom Netzwerk laden und cachen
  • Performance-Vorteil:

  • Instant Loading für gecachte Assets
  • Reduzierte Bandbreite
  • Funktioniert komplett offline
  • Navigation: Offline-Page als Fallback

    Ablauf:

  • Normale Navigation versuchen
  • Bei Netzwerkfehler: Offline-Seite anzeigen
  • Auto-Reconnect im Hintergrund
  • Was wird automatisch gecacht?

    Bei der Installation (Precaching)

    Folgende Ressourcen werden sofort beim ersten Besuch gecacht:

    Core-Assets:

    /                           # Startseite
    /offline                    # Offline-Fallback-Seite
    /_next/static/css/*.css     # Alle Stylesheets
    /_next/static/js/*.js       # JavaScript-Bundles
    /logo.png                   # Hotel-Logo
    /fonts/*.woff2              # Web-Schriften
    /manifest.json              # PWA-Manifest

    Größe: Typisch 2-3 MB

    Während des Betriebs (Runtime Caching)

    Diese Inhalte werden bei Nutzung automatisch gecacht:

    Flugdaten

    Endpoint: /api/flights/[hotelId]?type=departures
    Endpoint: /api/flights/[hotelId]?type=arrivals
    Cache-Dauer: Unbegrenzt (wird bei Update überschrieben)
    Größe: ~50KB pro Request

    Konfiguration

    Endpoint: /api/config/[hotelId]
    Cache-Dauer: Unbegrenzt
    Größe: ~5KB
    Update: Alle 60 Sekunden bei Online

    Wetterdaten (wenn aktiviert)

    Endpoint: /api/weather/[airportCode]
    Cache-Dauer: Unbegrenzt
    Größe: ~10KB
    Update: Alle 30 Minuten bei Online

    Hotel-Assets

    Logo: *.blob.vercel-storage.com/logo.png
    Info-Slide-Bilder: *.blob.vercel-storage.com/slides/*
    Cache-Dauer: 7 Tage
    Größe: Variable (100KB-1MB pro Bild)

    API-Response Caching Details

    Zeitstempel-System

    Jede gecachte API-Response erhält Metadaten:

    headers.set('sw-cached-at', '2024-01-15T10:30:00Z')
    headers.set('sw-cache-version', 'v1')
    headers.set('sw-original-url', request.url)

    Intelligente Cache-Nutzung

    Online-Verhalten:

  • Neue Daten vom Server holen
  • Cache aktualisieren
  • Alte Cache-Einträge überschreiben
  • Offline-Verhalten:

  • Neueste gecachte Version suchen
  • Alter prüfen (Information für Benutzer)
  • Daten anzeigen mit Offline-Indikator
  • Cache-Alterung und Frische

    Keine automatische Expiration!

    Caches verfallen nicht automatisch. Stattdessen:

  • Werden bei Online-Verbindung überschrieben
  • Zeigen Alter bei Offline-Nutzung an
  • Benutzer sieht "Daten von [Zeitpunkt]"
  • Visuelle Offline-Indikatoren

    LobbyFlight zeigt den Verbindungsstatus deutlich an:

    1. Status-Bar (Oberer Bildschirmrand)

    Offline-Modus aktiv:

    [Orange Bar] ⚠️ Offline Mode - Displaying cached flight data
    Last sync: 10:45 (15 minutes ago)

    Eigenschaften:

  • Farbe: Orange (#F59E0B)
  • Position: Fixed top
  • Z-Index: 9999 (immer sichtbar)
  • Animation: Pulse-Effekt
  • 2. Toast-Benachrichtigungen

    Bei Verbindungsverlust:

    [Rote Toast] ❌ Connection lost - Showing cached data

    Bei Wiederverbindung:

    [Grüne Toast] ✅ Connection restored - Updating data...

    Eigenschaften:

  • Dauer: 5 Sekunden (Online) / Permanent (Offline)
  • Position: Top-Right
  • Animation: Slide-in von rechts
  • 3. Corner-Indikator (Unten links)

    Pulsierender Punkt mit Label:

    🔴 Offline

    Animation:

    @keyframes pulse {
      0%, 100% { opacity: 1; }
      50% { opacity: 0.5; }
    }

    4. Daten-Aktualität-Anzeige

    Bei gecachten Daten wird das Alter angezeigt:

    Letzte Aktualisierung: vor 5 Minuten
    Flugdaten: Stand 10:45 Uhr
    Wetter: Stand 10:30 Uhr

    Automatische Wiederverbindung

    Zwei Mechanismen arbeiten parallel:

    1. Browser Online/Offline Events

    JavaScript Event Listener:

    window.addEventListener('online', () => {
      // Sofort Updates holen
      refreshAllData()
      showToast('Connection restored', 'success')
    })
    
    window.addEventListener('offline', () => {
      // Auf Cache-Modus wechseln
      enableOfflineMode()
      showToast('Connection lost', 'warning')
    })

    Vorteile:

  • Native Browser-API
  • Sofortige Erkennung
  • Keine zusätzlichen Requests
  • 2. Periodische Health-Checks

    Aktiver Connectivity-Test:

    setInterval(async () => {
      try {
        const response = await fetch('/api/health', {
          method: 'HEAD',
          cache: 'no-cache'
        })
        if (!response.ok) throw new Error()
        setOnlineStatus(true)
      } catch {
        setOnlineStatus(false)
      }
    }, 30000) // Alle 30 Sekunden

    Warum zusätzliche Health-Checks?

  • Browser-Events sind nicht immer zuverlässig
  • Erkennt Server-Probleme (nicht nur Netzwerk)
  • Verifiziert tatsächliche API-Verfügbarkeit
  • Offline-Page Auto-Reload

    Die Offline-Fallback-Seite versucht automatisch, die Verbindung wiederherzustellen:

    Reconnection-Strategie:

  • Erste 30 Sekunden: Alle 1 Sekunde
  • Nächste 90 Sekunden: Alle 5 Sekunden
  • Danach: Alle 30 Sekunden
  • Nach 5 Minuten: Manueller Reload erforderlich
  • JavaScript-Implementation:

    let attempts = 0
    const maxAttempts = 120
    
    function tryReconnect() {
      if (attempts >= maxAttempts) {
        showMessage('Please reload manually')
        return
      }
    
      fetch('/api/health')
        .then(() => window.location.reload())
        .catch(() => {
          attempts++
          const delay = attempts < 30 ? 1000 :
                       attempts < 60 ? 5000 : 30000
          setTimeout(tryReconnect, delay)
        })
    }

    Cache-Management

    Automatisches Cleanup

    Service Worker führt automatische Bereinigung durch:

    Bei Update der App:

  • Neue Service Worker Version wird installiert
  • Alte Cache-Versionen werden identifiziert
  • Veraltete Caches werden gelöscht
  • Neue Version wird aktiviert
  • Code:

    self.addEventListener('activate', event => {
      event.waitUntil(
        caches.keys().then(cacheNames => {
          return Promise.all(
            cacheNames
              .filter(name => name !== CURRENT_CACHE)
              .map(name => caches.delete(name))
          )
        })
      )
    })

    Manuelles Cache-Löschen

    Methode 1: Über Browser DevTools

  • Chrome öffnen → F12
  • Application Tab → Storage
  • Cache Storage → lobbyflight-v1
  • Rechtsklick → Delete
  • Methode 2: Über JavaScript Console

    // Alle Caches löschen
    caches.keys().then(names => {
      names.forEach(name => caches.delete(name))
    })
    
    // Service Worker neu registrieren
    navigator.serviceWorker.getRegistration().then(reg => {
      reg.unregister()
      window.location.reload()
    })

    Methode 3: Hard Refresh

  • Windows/Linux: Ctrl + Shift + F5
  • Mac: Cmd + Shift + R
  • Android Chrome: Settings → Privacy → Clear Browsing Data
  • Methode 4: Message API

    // Cache-Clear-Nachricht an Service Worker
    navigator.serviceWorker.controller.postMessage({
      type: 'CLEAR_CACHE',
      cache: 'all' // oder 'api', 'assets', 'runtime'
    })

    Cache-Größen-Management

    Browser-Limits:

  • Chrome: 6% des verfügbaren Speichers
  • Firefox: 10% des verfügbaren Speichers
  • Safari: 50MB initial, erweiterbar
  • LobbyFlight typische Nutzung:

  • Initial: 3-5 MB
  • Nach 1 Tag: 10-15 MB
  • Nach 1 Woche: 20-30 MB
  • Maximum: ~50 MB
  • Automatisches Eviction:

    Browser löscht automatisch alte Caches wenn:

  • Speicherplatz knapp wird
  • Andere Apps Speicher benötigen
  • Cache älter als 7 Tage ohne Nutzung
  • Troubleshooting Offline-Probleme

    Problem: Alte Daten werden angezeigt

    Symptome:

  • Flüge von gestern sichtbar
  • Wetter stimmt nicht
  • Konfiguration veraltet
  • Diagnose:

  • Chrome DevTools → Application → Cache Storage
  • Prüfen Sie 'sw-cached-at' Header
  • Vergleichen mit aktueller Zeit
  • Lösungen:

  • Hard Refresh (Ctrl+Shift+F5)
  • Cache manuell löschen
  • Service Worker neu registrieren
  • App neu installieren (PWA)
  • Problem: Offline-Modus trotz Internet

    Symptome:

  • Orange Offline-Bar permanent sichtbar
  • Health-Checks schlagen fehl
  • Aber Internet funktioniert
  • Diagnose:

  • Console → Network Tab
  • Suchen nach failed /api/health requests
  • Prüfen auf CORS oder TLS-Fehler
  • Lösungen:

  • Firewall-Regeln prüfen
  • Proxy-Konfiguration checken
  • DNS-Cache leeren
  • Browser neu starten
  • Problem: Service Worker lädt nicht

    Symptome:

  • Kein Offline-Modus verfügbar
  • Cache funktioniert nicht
  • PWA-Installation fehlgeschlagen
  • Diagnose:

    // In Console ausführen
    navigator.serviceWorker.getRegistrations().then(regs => {
      console.log('Registered SWs:', regs)
    })

    Lösungen:

  • HTTPS verwenden (zwingend!)
  • Localhost ist OK für Tests
  • Inkognito-Modus deaktivieren
  • Browser-Update durchführen
  • Problem: Cache wird zu groß

    Symptome:

  • Browser wird langsam
  • "Storage quota exceeded" Fehler
  • Display reagiert träge
  • Diagnose:

    // Cache-Größe prüfen
    navigator.storage.estimate().then(estimate => {
      console.log(`Used: ${estimate.usage / 1024 / 1024}MB`)
      console.log(`Quota: ${estimate.quota / 1024 / 1024}MB`)
    })

    Lösungen:

  • Alte Caches löschen
  • Bildgrößen optimieren
  • Cache-Strategie anpassen
  • Storage-Quota erhöhen (wenn möglich)
  • Best Practices für Offline-Betrieb

    Optimale Konfiguration

    Für stabiles Netzwerk:

  • Kurze Cache-Zeiten (5 Minuten)
  • Aggressive Updates
  • Minimal-Caching
  • Für instabiles Netzwerk:

  • Längere Cache-Zeiten (15-30 Minuten)
  • Mehr Precaching
  • Offline-First-Ansatz
  • Vorbereitung auf Offline

    Vor dem Deployment:

  • Display online vollständig laden lassen
  • Alle Tabs einmal durchklicken
  • 10 Minuten laufen lassen (füllt Caches)
  • Dann erst in finale Position
  • Regelmäßige Wartung:

  • Wöchentlich: Browser-Neustart
  • Monatlich: Cache-Clear
  • Quartal: Browser-Update
  • Monitoring

    Was überwachen:

  • Offline-Ereignisse pro Tag
  • Durchschnittliche Offline-Dauer
  • Cache-Hit-Rate
  • Failed API Requests
  • Alert-Schwellen:

  • > 10 Offline-Events/Tag
  • > 30 Minuten Offline am Stück
  • Cache-Size > 100MB
  • Hit-Rate < 50%
  • Erweiterte Konfiguration

    Custom Offline-Page

    Sie können eine eigene Offline-Seite gestalten:

    HTML-Template (/public/custom-offline.html):

    <!DOCTYPE html>
    <html>
    <head>
      <title>Offline - [Hotel Name]</title>
      <style>
        /* Ihr Custom Styling */
      </style>
    </head>
    <body>
      <div class="container">
        <img src="/logo.png" alt="Hotel Logo">
        <h1>Momentan keine Verbindung</h1>
        <p>Zeige gespeicherte Flugdaten...</p>
        <div id="last-update"></div>
      </div>
      <script>
        // Custom Reconnect-Logic
      </script>
    </body>
    </html>

    Cache-Strategien anpassen

    Für spezielle Anforderungen:

    // Längere Cache-Zeit für Bilder
    if (request.destination === 'image') {
      return caches.match(request) || fetch(request).then(response => {
        cache.put(request, response.clone())
        return response
      })
    }
    
    // Kein Cache für bestimmte APIs
    if (request.url.includes('/realtime/')) {
      return fetch(request) // Immer frisch
    }

    Offline-Analytics

    Tracking von Offline-Events:

    // Bei Offline
    navigator.sendBeacon('/api/analytics', JSON.stringify({
      event: 'offline_start',
      timestamp: new Date().toISOString(),
      cached_items: await countCachedItems()
    }))
    
    // Bei Reconnect
    navigator.sendBeacon('/api/analytics', JSON.stringify({
      event: 'offline_end',
      duration: offlineDuration,
      cache_hits: cacheHitCount
    }))

    Was this article helpful?