diff options
| author | Christian Cleberg <[email protected]> | 2026-05-06 20:41:49 -0500 |
|---|---|---|
| committer | Christian Cleberg <[email protected]> | 2026-05-06 20:41:49 -0500 |
| commit | 205cf2687ce48f3d004792ff223422a86cc6bdbc (patch) | |
| tree | 7edb78cede354e79aa8abd764ed9c5047e0ee168 /Hutch/Views/Builds/BuildListViewModel.swift | |
| parent | 57e4f34b4613c09beb0cb757ac2ba2b43cc04daf (diff) | |
| download | hutch-3.3.1.tar.gz hutch-3.3.1.tar.bz2 hutch-3.3.1.zip | |
feat(cache): persist read-only API responsesv3.3.1
Add a bounded stale-while-revalidate cache at the Sourcehut API boundary with
stable keys, centralized TTLs, request coalescing, payload hashing, and LRU disk
pruning.
Cache high-value read-only repo, build, ticket, project, profile, paste, and
Home/Work Queue data while keeping mutations network-only and invalidating
related prefixes after successful writes.
Add focused cache tests and implementation notes.
Diffstat (limited to 'Hutch/Views/Builds/BuildListViewModel.swift')
| -rw-r--r-- | Hutch/Views/Builds/BuildListViewModel.swift | 23 |
1 files changed, 17 insertions, 6 deletions
diff --git a/Hutch/Views/Builds/BuildListViewModel.swift b/Hutch/Views/Builds/BuildListViewModel.swift index 14f50fd..42500a8 100644 --- a/Hutch/Views/Builds/BuildListViewModel.swift +++ b/Hutch/Views/Builds/BuildListViewModel.swift @@ -188,7 +188,7 @@ final class BuildListViewModel { func loadJobs() async { // Show cached data immediately on first load (may populate `jobs` from cache). if jobs.isEmpty { - loadFromCache() + await loadFromCache() } let treatAsInitialLoad = jobs.isEmpty @@ -279,6 +279,7 @@ final class BuildListViewModel { variables: variables, responseType: SubmitJobResponse.self ) + await invalidateBuildListCache() await loadJobs() return result.submit.id } catch { @@ -297,6 +298,7 @@ final class BuildListViewModel { variables: ["id": job.id], responseType: CancelResponse.self ) + await invalidateBuildListCache() if let index = jobs.firstIndex(where: { $0.id == job.id }) { let updated = JobSummary( id: job.id, @@ -345,14 +347,17 @@ final class BuildListViewModel { } if useCache && cursor == nil { - let result = try await client.executeAndCache( + let cached = try await client.executeCached( service: .builds, query: Self.query, variables: variables.isEmpty ? nil : variables, responseType: JobsResponse.self, - cacheKey: Self.cacheKey + cacheKey: APICacheKeys.builds(cursor: cursor), + resourceType: .buildList, + ttl: APICacheTTLs.activeBuild, + policy: .cacheFirstThenRefresh ) - return result.jobs + return cached.value.jobs } else { let result = try await client.execute( service: .builds, @@ -364,8 +369,14 @@ final class BuildListViewModel { } } - private func loadFromCache() { - guard let data = client.responseCache.get(forKey: Self.cacheKey) else { return } + private func invalidateBuildListCache() async { + await client.invalidateCache(prefix: APICacheKeys.prefix(SRHTService.builds.rawValue, "jobs")) + await client.invalidateCache(prefix: APICacheKeys.prefix(SRHTService.builds.rawValue, "job")) + await client.invalidateCache(prefix: APICacheKeys.prefix("home")) + } + + private func loadFromCache() async { + guard let data = await client.cachedPayload(forKey: APICacheKeys.builds()) ?? client.responseCache.get(forKey: Self.cacheKey) else { return } let decoder = JSONDecoder() decoder.dateDecodingStrategy = .srhtFlexible if let response = try? decoder.decode( |
