refactor(core): reuse catalog response digest (#46071)

This commit is contained in:
Kit Langton
2026-08-28 23:41:49 -04:00
committed by GitHub
Unverified
parent 7852cecd72
commit cf2c3a536d
2 changed files with 17 additions and 6 deletions
+5 -4
View File
@@ -636,8 +636,8 @@ export const layer = (options?: Options) =>
// population. The payload has outgrown some KV backends' per-value
// limits (Durable Object SQLite caps values at 2 MB and api.json
// passed it in Aug 2026); a boot without a cache hit just refetches.
const writeCache = Effect.fn("ModelsDev.writeCache")(function* (text: string) {
yield* kv.set(key, { updatedAt: Date.now(), digest: bodyDigest(text), body: text }).pipe(
const writeCache = Effect.fn("ModelsDev.writeCache")(function* (text: string, digest = bodyDigest(text)) {
yield* kv.set(key, { updatedAt: Date.now(), digest, body: text }).pipe(
Effect.catchCauseIf(
(cause) => !Cause.hasInterruptsOnly(cause),
(cause) => Effect.logWarning("Failed to cache models.dev catalog", { cause }),
@@ -681,12 +681,13 @@ export const layer = (options?: Options) =>
const stored = yield* loadFromCache()
if (!force && stored && Date.now() - stored.updatedAt < Duration.toMillis(ttl)) return
const text = yield* fetchApi()
const digest = bodyDigest(text)
// models.dev rarely changes between polls; skip the cache write,
// invalidation, and Refreshed event for a byte-identical body so
// downstream catalog.updated listeners stay quiet.
if (!force && stored?.digest === bodyDigest(text)) return
if (!force && stored?.digest === digest) return
yield* decodeCatalog(text)
yield* writeCache(text)
yield* writeCache(text, digest)
yield* invalidate
yield* bus.publish(ModelsDev.Event.Refreshed, {})
}),
+12 -2
View File
@@ -297,7 +297,10 @@ describe("ModelsDev Service", () => {
const context = yield* Layer.build(buildLayer(state, cache, { fetch: true, snapshot: false }))
const result = yield* ModelsDev.Service.use((s) => s.get()).pipe(Effect.provide(context))
expect(result).toEqual(fixture2Snapshot)
expect(cache.values.get(cacheKey)).toMatchObject({ body: JSON.stringify(fixture2) })
expect(cache.values.get(cacheKey)).toMatchObject({
body: JSON.stringify(fixture2),
digest: bodyDigest(JSON.stringify(fixture2)),
})
const final = yield* Ref.get(state)
expect(final.calls.length).toBe(1)
}),
@@ -387,7 +390,10 @@ describe("ModelsDev Service", () => {
)
expect(result.before).toEqual(fixtureSnapshot)
expect(result.after).toEqual(fixture2Snapshot)
expect(cache.values.get(cacheKey)).toMatchObject({ body: JSON.stringify(fixture2) })
expect(cache.values.get(cacheKey)).toMatchObject({
body: JSON.stringify(fixture2),
digest: bodyDigest(JSON.stringify(fixture2)),
})
const final = yield* Ref.get(state)
expect(final.calls.length).toBe(1)
expect(final.calls[0].url).toContain("/api.json")
@@ -440,6 +446,10 @@ describe("ModelsDev Service", () => {
const final = yield* Ref.get(state)
expect(final.calls.length).toBe(1)
expect(after).toEqual(fixture2Snapshot)
expect(cache.values.get(cacheKey)).toMatchObject({
body: JSON.stringify(fixture2),
digest: bodyDigest(JSON.stringify(fixture2)),
})
}),
)