Otomatik yeniden deneme
Riverpod'da Provider'lar başarısız olduklarında otomatik olarak yeniden denenir.
Provider'ın hesaplaması sırasında bir istisna fırlatıldığında yeniden deneme yapılır. Yeniden deneme mantığı, provider bazında veya tüm provider'lar için global olarak özelleştirilebilir.
Varsayılan olarak bir provider en fazla 10 kez, 200 ms'den 6,4 saniyeye kadar üstel olarak artan bir bekleme süresiyle yeniden denenir. Varsayılan yeniden deneme mantığının tüm ayrıntıları için retry belgesine bakın.
Yeniden deneme mantığını özelleştirmek
Özel bir yeniden deneme mantığı, uygulamanın tamamı için veya belirli bir provider için sağlanabilir.
Her iki durumda da uygulama aynıdır: Özel yeniden deneme mantığı, bir sonraki denemeden önceki
gecikmeyi belirten bir Duration? değeri döndürmesi beklenen bir fonksiyondur (yeniden denemeyi
durdurmak için null döndürülür).
Aşağıdaki kod, en fazla 5 kez yeniden deneyen, 200 ms'den başlayan üstel bir bekleme süresi kullanan ve ProviderException hatalarını göz ardı eden özel bir retry fonksiyonu tanımlar
Duration? myRetry(int retryCount, Object error) {
// ProviderException durumunda yeniden denemeyi durdur
if (retryCount >= 5) return null;
// ProviderException'ı göz ardı et
if (error is ProviderException) return null;
return Duration(milliseconds: 200 * (1 << retryCount)); // Üstel bekleme süresi
}
Bu fonksiyon daha sonra, ilgili provider'ın yeniden deneme mantığını güncellemek için provider'ların içinde kullanılabilir:
- riverpod
- riverpod_generator
final myProvider = Provider<int>(
retry: myRetry,
(ref) => 0,
);
(retry: myRetry)
int myProvider(MyProviderRef ref) {
return 0;
}
Ya da ProviderContainers/ProviderScopes bileşenine iletilerek global olarak kullanılabilir:
// Saf Dart kodu için
final container = ProviderContainer(
retry: myRetry,
);
...
// Flutter kodu için
runApp(
ProviderScope(
retry: myRetry,
child: MyApp(),
),
);
Yeniden denemeyi devre dışı bırakmak
Yeniden denemeyi devre dışı bırakmak, yeniden deneme fonksiyonunda her zaman null döndürmek kadar basittir.
Uygulamanızın tamamı için yeniden denemeyi devre dışı bırakmak isterseniz şunu yapın:
runApp(
ProviderScope(
retry: (retryCount, error) => null,
child: MyApp(),
),
);
Varsayılan yeniden deneme mantığı hakkında
Varsayılan yeniden deneme mantığı, saf bir "başarısız olursa yeniden dene" yaklaşımından daha akıllı olacak şekilde tasarlanmıştır. Özellikle Error ve ProviderException türlerini yeniden denemez.
Error'lar yeniden denenmez, çünkü kurtarılabilir değildirler. Koddaki bir hataya işaret ederler ve yeniden denemek işe yaramaz. Bu durumlarda yeniden denemek, günlükleri gereksiz deneme kayıtlarıyla kirletmekten başka bir işe yaramaz.
ProviderException'lara gelince, bunlar yeniden denenmez; çünkü bir provider'ın kendisinin başarısız olduğunu değil, başarısız olan bir provider'dan gelen istisnayı yeniden fırlattığını gösterirler. Şunu düşünün:
- riverpod
- riverpod_generator
final failedProvider = Provider<int>(
(ref) => throw Exception('This provider always fails'),
);
final myProvider = Provider<int>(
// Bu provider, başarısız olan bir provider'a bağımlıdır
// ve bu nedenle bir ProviderException fırlatacaktır
(ref) => ref.watch(failedProvider),
);
int failed(MyProviderRef ref) {
throw Exception('This provider always fails');
}
int myProvider(MyProviderRef ref) {
// Bu provider, başarısız olan bir provider'a bağımlıdır
// ve bu nedenle bir ProviderException fırlatacaktır
return ref.watch(failedProvider);
}
Bu örnekte, myProvider başarısız olsa da bu başarısızlıktan o sorumlu değildir.
Onu yeniden denemek işe yaramaz. Bunun yerine yeniden denenmesi gereken failedProvider'dır.
Bu da şu anlama gelir: failedProvider için yeniden denemeyi devre dışı bırakırsanız, myProvider da yeniden denenmez.
Yeniden denemelerin tamamlanmasını beklemek
FutureProvider.future kullanarak asenkron provider'ların tamamlanmasını bekleyebileceğinizi biliyor olabilirsiniz:
final value = await ref.watch(myProvider.future);
Peki otomatik yeniden denemenin bununla nasıl etkileşime girdiğini merak ediyor olabilirsiniz.
Kısaca, asenkron bir provider başarısız olup yeniden denendiğinde, ilişkili future şu iki durumdan biri gerçekleşene kadar beklemeyi sürdürür:
- tüm yeniden denemeler tükenene kadar veya
- provider başarılı olana kadar.
Bu, await ref.watch(myProvider.future) ifadesinin aradaki başarısızlıkları atlamasını sağlar.