Data & offline
kinetica-data layers real-world data concerns over the core resource loop: retries, optimistic mutations, pagination, and offline caches.
Retry
val user = retry(RetryPolicy(attempts = 3, delayMillis = 250, backoffMultiplier = 2.0)) { attempt ->
api.loadUser()
}
resource(UserKey) { api.loadUser() }.awaitWithRetry(RetryPolicy(attempts = 3))RetryPolicy computes exponential backoff capped at maxDelayMillis; shouldRetry filters which failures are worth retrying. Coroutine cancellation always rethrows immediately — a cancelled retry loop never spins. awaitWithRetry invalidates the resource between attempts so each retry re-runs the loader.
Optimistic actions
val addTodo = optimisticAction(
invalidates = { listOf(TodosKey) },
optimistic = { title -> todos = todos + title }, // apply immediately
rollback = { title, error -> todos = todos - title }, // undo on failure
) { title ->
api.createTodo(title)
}
addTodo("Ship docs") // UI updates instantly; rolls back + rethrows if the API failsOn success the declared resource keys invalidate, so canonical data replaces the optimistic version through the normal resource loop.
Pagination
val pager = paginator<Article>(key = "feed")
launchEffect {
pager.loadNext { request -> api.articles(offset = request.offset, limit = request.limit) }
}
lazyEach(pager.asLazyItems(), key = { it.id }) { article -> ArticleRow(article) }
text(if (pager.canLoadMore) "Scroll for more" else "That's all")Paginator tracks items, isLoading, error, totalCount and canLoadMore; a loader returns Page(items, next, totalCount) and isEnd falls out of next == null. asLazyItems() plugs straight into lazyEach.
Offline cache
val cache = InMemoryOfflineCache<String, Orders>()
// serve cache when present, otherwise fetch:
val fast = cache.load("orders", strategy = OfflineStrategy.CacheFirst) { api.orders() }
// prefer fresh, degrade to stale cache when offline:
val load = cache.load("orders", strategy = OfflineStrategy.NetworkFirst) { api.orders() }
if (load.stale) showOfflineBanner(load.failure)OfflineLoad reports where the value came from (source: Cache | Network), whether it is stale (network failed, cache served), and the underlying failure. Implement OfflineCache over any storage; the in-memory one is the reference. Cancellation is never swallowed into a stale-cache fallback.