flexible<T> method

Future<T> flexible<T>(
  1. String key,
  2. Duration fresh,
  3. Duration? stale,
  4. FutureOr<T> compute(), {
  5. T decode(
    1. Object? json
    )?,
})

Stale while revalidate. The value is fresh for fresh. After that it is stale for stale more: it is still returned right away, and one caller refreshes it in the background. After fresh + stale it is gone, and the next call waits for compute.

A null stale keeps the value until a refresh replaces it. Use it when an old value beats none, like rates from a provider that can be down: when compute fails, callers still get the last good value. decode works like in remember. The driver must support locks.

int count = await cache.flexible<int>(
  'users',
  Duration(minutes: 5),
  Duration(minutes: 10),
  countUsers,
);

Implementation

Future<T> flexible<T>(
  String key,
  Duration fresh,
  Duration? stale,
  FutureOr<T> Function() compute, {
  T Function(Object? json)? decode,
}) async {
  String fullKey = await itemKey(key);
  String createdKey = '${CacheConstants.flexibleCreatedPart}$fullKey';
  Map<String, dynamic> found = await driver.many(<String>[
    fullKey,
    createdKey,
  ]);
  Object? cached = found[fullKey];
  Object? created = found[createdKey];
  if (cached == null || created is! int) {
    return await _once<T>(
      fullKey,
      () => _computeFlexible<T>(fullKey, createdKey, fresh, stale, compute),
    );
  }
  if (clock.nowMs() - created >= fresh.inMilliseconds) {
    _refreshFlexible<T>(fullKey, createdKey, fresh, stale, compute).ignore();
  }
  return _decode<T>(cached, decode);
}