Invalidate async cache on exception (#132)

* Invalidate async cache on exception

When the callback throws an exception, the startStaleTime was not called, so the cache was not refreshed. Because of this, future calls to this cache returned with the exception.
diff --git a/lib/src/async_cache.dart b/lib/src/async_cache.dart
index d6f5f7f..99b3881 100644
--- a/lib/src/async_cache.dart
+++ b/lib/src/async_cache.dart
@@ -60,12 +60,12 @@
     if (_cachedStreamSplitter != null) {
       throw StateError('Previously used to cache via `fetchStream`');
     }
-    if (_cachedValueFuture == null) {
-      _cachedValueFuture = callback();
-      await _cachedValueFuture;
+    final result = _cachedValueFuture ??= callback();
+    try {
+      return await result;
+    } finally {
       _startStaleTimer();
     }
-    return _cachedValueFuture!;
   }
 
   /// Returns a cached stream from a previous call to [fetchStream], or runs
diff --git a/test/async_cache_test.dart b/test/async_cache_test.dart
index 81e43e1..3ceda79 100644
--- a/test/async_cache_test.dart
+++ b/test/async_cache_test.dart
@@ -158,4 +158,16 @@
     }));
     expect(cache.fetchStream(call).toList(), completion(['1', '2', '3']));
   });
+
+  test('should invalidate even if the future throws an exception', () async {
+    cache = AsyncCache.ephemeral();
+
+    Future<String> throwingCall() async => throw Exception();
+    await expectLater(cache.fetch(throwingCall), throwsA(isException));
+    // To let the timer invalidate the cache
+    await Future.delayed(Duration(milliseconds: 5));
+
+    Future<String> call() async => 'Completed';
+    expect(await cache.fetch(call), 'Completed', reason: 'Cache invalidates');
+  });
 }