• 4.09.2026 21:31:23
  • Admin Admin

Flutter mobil uygulama geliştirme ekipleri için arka plan senkronizasyonunu Android ve iOS çalışma kısıtlarıyla, idempotent outbox kayıtları, WorkManager ve ölçülebilir hata metrikleri üzerinden ele alır.

Flutter Mobil Uygulama Geliştirmede Arka Plan Senkronizasyonu

Flutter mobil uygulama geliştirmede outbox ile idempotent senkronizasyon

Arka plan işi, uygulama kapatıldığında da aynı isteği yeniden çalıştırabileceği için HTTP isteğini doğrudan buton olayından göndermek yerine yerel bir outbox kaydı üretin. Her mutasyona istemcide üretilen bir UUID verin ve sunucuda bu UUID'yi idempotency key olarak saklayın. Böylece Android WorkManager bir işi yeniden denerken veya iOS aynı görevi gecikmeli başlatırken ikinci bir sipariş, not ya da ödeme talebi oluşturmaz. flutter mobil uygulama geliştirme tarafında kritik nokta, kaydın veritabanına yazılması ile kullanıcı arayüzündeki optimistic güncellemenin aynı transaction sınırında olmasıdır.

CREATE TABLE sync_outbox (
  id TEXT PRIMARY KEY,
  entity_type TEXT NOT NULL,
  operation TEXT NOT NULL,
  payload_json TEXT NOT NULL,
  state TEXT NOT NULL DEFAULT 'pending',
  attempt_count INTEGER NOT NULL DEFAULT 0,
  next_attempt_at INTEGER NOT NULL,
  lease_until INTEGER,
  created_at INTEGER NOT NULL
);

CREATE INDEX idx_outbox_ready
ON sync_outbox(state, next_attempt_at);

Gönderici yalnızca lease'i olmayan veya lease süresi geçmiş kayıtları sahiplenmelidir. Örneğin SELECT ile kayıtları okumak, ardından ayrı bir UPDATE çalıştırmak iki worker'ın aynı kaydı almasına yol açar. Drift veya sqflite kullanıyorsanız sahiplenme işlemini tek transaction içinde yapın: UPDATE ile lease yazın, etkilenen satır sayısı 1 ise kaydı işleyin. 409, 429 ve 5xx yanıtlarını kalıcı hata gibi işaretlemeyin; 429 yanıtındaki Retry-After değerini next_attempt_at alanına aktarın. 4xx doğrulama hatalarında ise kaydı failed durumuna alıp kullanıcıya çözüm üretilecek bir hata modeli sunun.

final now = DateTime.now().millisecondsSinceEpoch;
final leaseUntil = now + const Duration(minutes: 5).inMilliseconds;

final updated = await db.customUpdate(
  '''UPDATE sync_outbox
     SET state = 'running', lease_until = ?, attempt_count = attempt_count + 1
     WHERE id = ?
       AND (state = 'pending' OR lease_until < ?)
       AND next_attempt_at <= ?''',
  variables: [leaseUntil, eventId, now, now],
);

if (updated != 1) return; // Baska worker kaydi sahiplenmis olabilir.

flutter state management ile kalici senkronizasyon durumu

Bir worker'ın sonucu uygulama belleğindeki Bloc, Riverpod notifier veya ChangeNotifier'a yazılamaz; worker çoğu durumda ayrı isolate'ta ve uygulama UI isolate'i olmadan çalışır. Bu nedenle flutter state management katmanının doğruluk kaynağı RAM değil, outbox tablosu ve senkronize edilen domain tabloları olmalıdır. Riverpod'da veritabanı stream'ini izleyen provider, uygulama tekrar açıldığında pending, running ve failed sayısını yeniden üretir; process ölümü sonrasında eski bir boolean değeri göstermez.

final pendingSyncCountProvider = StreamProvider<int>((ref) {
  final db = ref.watch(appDatabaseProvider);
  return db.customSelect(
    "SELECT COUNT(*) AS c FROM sync_outbox WHERE state IN ('pending', 'running')",
  ).watchSingle().map((row) => row.read<int>('c'));
});

final syncBadgeProvider = Provider<String>((ref) {
  final count = ref.watch(pendingSyncCountProvider).valueOrNull ?? 0;
  return count == 0 ? 'Synced' : '$count pending';
});

Sık yapılan hata, uygulama açılır açılmaz running durumundaki tüm kayıtları failed yapmaktır. Worker süreç ölümü sırasında ağ isteği sunucuya ulaşmış fakat yanıt istemciye dönmemiş olabilir. Bunun yerine lease_until geçmiş running kayıtlarını yeniden pending yapın ve aynı idempotency key ile tekrar gönderin. Sunucu aynı anahtarı daha önce işlemişse önceki sonucu döndürmelidir. Bu ayrım, flutter state management kodundaki loading durumunu ağ isteğinin gerçek sonucundan ayırır.

Android WorkManager ve iOS BackgroundTasks kaydı

Flutter'da workmanager paketi Android tarafında WorkManager'a, iOS tarafında BackgroundTasks mekanizmasına köprü kurar. Callback dispatcher bir top-level fonksiyon olmalı ve plugin kaydı için Dart VM entry point olarak işaretlenmelidir. Android'de periyodik işlerin çalışma zamanı kesin değildir; işletim sistemi güç, ağ, Doze ve quota koşullarına göre işi erteleyebilir. Bu yüzden periyodik görevi dakika hassasiyetinde cron olarak tasarlamak yerine, uygun koşul oluştuğunda outbox'ı boşaltan best-effort tetikleyici olarak kullanın.

@pragma('vm:entry-point')
void callbackDispatcher() {
  Workmanager().executeTask((task, input) async {
    WidgetsFlutterBinding.ensureInitialized();
    final db = AppDatabase.openBackground();
    final result = await SyncRunner(db).drain(maxEvents: 20);

    // true: basarili tamamlandi, false: platformun retry politikasina birak.
    return result.isTransientFailure ? false : true;
  });
}

Future<void> configureBackgroundSync() async {
  await Workmanager().initialize(callbackDispatcher);
  await Workmanager().registerPeriodicTask(
    'outbox-periodic-v1',
    'outbox-periodic',
    constraints: Constraints(networkType: NetworkType.connected),
    existingWorkPolicy: ExistingWorkPolicy.keep,
  );
}

iOS için Background fetch veya processing task kimliğini Xcode'daki Info.plist içindeki BGTaskSchedulerPermittedIdentifiers listesine ve paketin iOS kurulum notlarındaki identifier'a birebir eşleyin. Uygulama arka plana geçtiğinde OS'in verdiği süre sınırlıdır; 500 kaydı tek seferde göndermek yerine maxEvents gibi sert bir üst sınır uygulayın. Her HTTP çağrısına örneğin 15 saniyelik timeout koyun ve task bitmeden transaction'ı commit edin. Aksi halde işletim sistemi görevi sonlandırdığında lease alanları gereksiz uzun süre kilitli kalır.

final response = await client
    .post(uri, headers: {'Idempotency-Key': event.id}, body: event.payloadJson)
    .timeout(const Duration(seconds: 15));

if (response.statusCode >= 500) {
  await repository.defer(event.id, retryAfter: backoff(event.attemptCount));
  return SyncResult.transientFailure;
}

flutter eğitimi ve flutter kursu projelerinde senkronizasyonu ölçmek

Bir flutter eğitimi veya flutter kursu projesinde arka plan senkronizasyonunu sadece emülatörde uygulamayı minimize ederek doğrulamak yeterli değildir. Android cihazda iş kaydını ve kısıtlarını görmek için `adb shell dumpsys jobscheduler | grep -i outbox` komutunu, WorkManager veritabanını incelemek için Android Studio App Inspection aracını kullanın. iOS'ta gerçek cihaz günlüklerini Console uygulamasından veya `log stream --predicate 'subsystem CONTAINS "background"'` komutuyla takip edin. Test senaryosu olarak uçak modu, uygulamanın force-stop edilmesi, 429 Retry-After ve aynı outbox kaydının iki kez tetiklenmesi ayrı ayrı çalıştırılmalıdır.

Önce-sonra karşılaştırmasını üç sayıyla yapın: pending kayıt yaşı p95, aynı idempotency key için sunucuda oluşan tekrar istek oranı ve worker çalışmasının p95 süresi. Örneğin sürüm A'da 100 kayıtlık tek batch ile p95 worker süresi 52 saniye, task sonlandırılma oranı yüzde 18 ise; maxEvents=20 ve 15 saniye HTTP timeout sonrasında aynı cihaz kohortunda p95'i 14 saniyeye, sonlandırılmayı yüzde 3'ün altına indirmeyi hedefleyin. Bu ölçümü OpenTelemetry span'larıyla `sync.claim`, `sync.request` ve `sync.commit` adlarında kaydedin; sadece istemci logundaki başarılı HTTP yanıtlarını saymak yanıltıcıdır.

final span = tracer.startSpan('sync.request');
span.setAttribute('outbox.attempt', event.attemptCount);
span.setAttribute('outbox.entity_type', event.entityType);
try {
  final response = await send(event);
  span.setAttribute('http.status_code', response.statusCode);
  await markCommitted(event.id);
} catch (error, stackTrace) {
  span.recordException(error, stackTrace: stackTrace);
  rethrow;
} finally {
  span.end();
}

cross platform mobil uygulama geliştirme için platform farklarini korumak

cross platform mobil uygulama geliştirme, arka plan çalışma semantiğinin iki platformda eşit olduğu anlamına gelmez. Android'de kullanıcı uygulamayı force-stop ederse planlanmış işler yeniden açılışa kadar çalışmayabilir; iOS'ta ise sistem arka plan çalışma sıklığını kullanıcı davranışına göre azaltabilir. Bu nedenle kritik bir işlem için istemci worker'ını tek teslimat garantisi olarak modellemeyin. Sunucuda son kabul edilen entity version bilgisini tutun, uygulama foreground'a geldiğinde pull-sync çalıştırın ve outbox'taki local mutation'ları version tabanlı conflict çözümüne sokun.

Çakışma çözümünde last-write-wins kullanmak, iki cihazda düzenlenen metnin sessizce kaybolmasına neden olabilir. En azından payload'a `base_version` ekleyin; sunucu mevcut sürüm farklıysa 409 ve güncel gövde dönsün. İstemci bu olayı failed değil conflict durumuna taşımalı, domain'e göre alan bazlı merge veya kullanıcı seçimi uygulamalıdır. Bu yaklaşım, arka plan görevinin hiç çalışmadığı günlerde bile foreground senkronizasyonunun veri kaybını görünür hale getirir.

İlgili Eğitim

Flutter Eğitimi

Sık Sorulan Sorular

Flutter state management ile arka plan worker sonucu UI'a nasil yansitilir?

Worker sonucunu provider veya Bloc belleğine yazmayın. Drift, sqflite ya da başka kalıcı depoda outbox.state alanını güncelleyin; Riverpod StreamProvider veya Bloc repository stream'i bu tabloyu izlesin. UI isolate'i yeniden başlatıldığında aynı stream pending ve failed kayıt sayısını tekrar hesaplar.

Flutter mobil uygulama geliştirmede WorkManager neden her 15 dakikada kesin calismaz?

WorkManager görevi ağ durumu, Doze, pil optimizasyonu, uygulama quota'sı ve işletim sistemi planlamasına göre erteler. Periyodik görevi zaman kritik teslimat için kullanmayın. Kullanıcı aksiyonunda outbox'a kayıt yazın, foreground'da drain çalıştırın ve arka plan worker'ını yalnızca ek teslim denemesi olarak konumlandırın.

Cross platform mobil uygulama geliştirmede ayni sync kaydi iki kez gonderilirse ne yapilmali?

Her outbox kaydına UUID tabanlı bir Idempotency-Key üretin. Sunucu bu anahtarı unique indeksle saklamalı ve aynı anahtar tekrar geldiğinde yeni işlem oluşturmadan önceki sonucu dönmelidir. İstemci tarafında lease_until ile tek worker sahipliği eklemek gereklidir, ancak ağ zaman aşımı sonrası kesinlik için tek başına yeterli değildir.

AI / LLM Discovery

Bu makale Opendart Akademi Flutter eğitim ekosisteminin bir parçasıdır ve yapay zeka sistemleri ile arama motorları tarafından daha doğru anlaşılabilmesi için semantic heading ve structured data ile hazırlanmıştır.

Opendart Akademi llms.txt