also looking at this
fix: hydrate durable registry snapshots before serving writes
#244
11 files
+202
-35
Review threads live on the whole diff, not on one commit, so none are shown here - a thread's line means something in the branch's final form, and painting it into an intermediate step would put it on code it is not about.
| @@ -179,6 +179,7 @@ export class BuildStatusStore { | ||
| 179 | 179 | private unavailable = new Map<string, UnavailableVersion>() |
| 180 | 180 | private snapshot: ObjectSnapshot |
| 181 | 181 | private coverageSnapshot: ObjectSnapshot |
| 182 | private hydrated = false | |
| 182 | 183 | |
| 183 | 184 | // Derived coverage cache (domain -> version -> set of platforms) + freshness. |
| 184 | 185 | private coverage = new Map<string, Map<string, Set<string>>>() |
| @@ -203,8 +204,18 @@ export class BuildStatusStore { | ||
| 203 | 204 | private logs = new Map<string, BuildLogLine[]>() |
| 204 | 205 | |
| 205 | 206 | constructor(private s3: S3Client, private bucket: string) { |
| 206 | this.snapshot = new ObjectSnapshot(s3, bucket, 'build-status/status.json', () => this.captureState()) | |
| 207 | this.coverageSnapshot = new ObjectSnapshot(s3, bucket, 'build-status/coverage.json', () => this.captureCoverage()) | |
| 207 | this.snapshot = new ObjectSnapshot(s3, bucket, 'build-status/status.json', () => { | |
| 208 | this.assertHydrated() | |
| 209 | return this.captureState() | |
| 210 | }) | |
| 211 | this.coverageSnapshot = new ObjectSnapshot(s3, bucket, 'build-status/coverage.json', () => { | |
| 212 | this.assertHydrated() | |
| 213 | return this.captureCoverage() | |
| 214 | }) | |
| 215 | } | |
| 216 | ||
| 217 | private assertHydrated(): void { | |
| 218 | if (!this.hydrated) throw new Error('Build status snapshots have not been applied') | |
| 208 | 219 | } |
| 209 | 220 | |
| 210 | 221 | /** |
| @@ -312,6 +323,7 @@ export class BuildStatusStore { | ||
| 312 | 323 | } |
| 313 | 324 | |
| 314 | 325 | async load(): Promise<void> { |
| 326 | this.hydrated = false | |
| 315 | 327 | const [state, coverage] = await Promise.all([ |
| 316 | 328 | this.snapshot.load() as Promise<PersistedState | null>, |
| 317 | 329 | this.coverageSnapshot.load() as Promise<PersistedCoverage | null>, |
| @@ -344,6 +356,7 @@ export class BuildStatusStore { | ||
| 344 | 356 | if (event.state === 'built' && event.version) |
| 345 | 357 | this.mergeCoverage(event.domain, event.version, event.platform, new Date(event.ts).toISOString()) |
| 346 | 358 | } |
| 359 | this.hydrated = true | |
| 347 | 360 | } |
| 348 | 361 | |
| 349 | 362 | private key(e: { domain: string, version: string, platform: string }): string { |