invalidation_coordinator 0.1.0
invalidation_coordinator: ^0.1.0 copied to clipboard
Coalesces keyed invalidations into serialized reconciliation batches with trailing execution and graceful shutdown.
example/invalidation_coordinator_example.dart
import 'dart:async';
import 'package:invalidation_coordinator/invalidation_coordinator.dart';
enum Resource { profile, inbox, transactions }
Future<void> main() async {
final firstRefreshStarted = Completer<void>();
var invocation = 0;
final coordinator = InvalidationCoordinator<Resource>(
handler: (resources) async {
invocation++;
print('Batch $invocation: ${_names(resources)}');
if (invocation == 1) firstRefreshStarted.complete();
await _refresh(resources);
},
onError: (resources, error, stackTrace) {
print('Refresh failed for ${_names(resources)}: $error');
},
);
// Duplicate profile signals collapse into the first snapshot.
coordinator.invalidate(Resource.profile);
coordinator.invalidateAll([Resource.inbox, Resource.profile]);
await firstRefreshStarted.future;
// These arrive while the first batch is running. They become one trailing
// snapshot; profile is eligible again because its earlier attempt is active.
coordinator.invalidate(Resource.profile);
coordinator.invalidateAll([Resource.transactions, Resource.profile]);
await coordinator.idle;
print('All accepted refresh work is idle.');
await coordinator.close();
print('Coordinator closed.');
}
Future<void> _refresh(Set<Resource> resources) async {
// Replace this delay with application-specific API or database work.
await Future<void>.delayed(const Duration(milliseconds: 20));
}
String _names(Set<Resource> resources) {
final names = resources.map((resource) => resource.name).toList()..sort();
return names.join(', ');
}