mirror of
https://github.com/langgenius/dify.git
synced 2026-08-01 09:50:50 +08:00
68 lines
2.3 KiB
TypeScript
68 lines
2.3 KiB
TypeScript
import type { Store } from '@/store/store'
|
|
import { CACHE_COMPAT, getCache } from '@/store/manager'
|
|
|
|
// How long a host stays "known compatible" before difyctl re-probes /_version.
|
|
export const COMPAT_TTL_MS = 60 * 60 * 1000
|
|
|
|
// Only *positive* (compatible) verdicts are cached — never "too old". A host that
|
|
// was too old is re-probed every time, so a just-upgraded server clears a previous
|
|
// block immediately instead of staying locked out for the whole TTL.
|
|
const COMPATIBLE_KEY = { key: 'compatible', default: {} as Record<string, string> } as const
|
|
|
|
export type CompatStore = {
|
|
readonly isFreshCompatible: (host: string, now?: Date) => boolean
|
|
readonly markCompatible: (host: string, now?: Date) => Promise<void>
|
|
}
|
|
|
|
export type CompatStoreOptions = {
|
|
readonly store?: Store
|
|
readonly now?: () => Date
|
|
readonly ttlMs?: number
|
|
}
|
|
|
|
export async function loadCompatStore(opts: CompatStoreOptions = {}): Promise<CompatStore> {
|
|
const store = opts.store ?? getCache(CACHE_COMPAT)
|
|
const ttlMs = opts.ttlMs ?? COMPAT_TTL_MS
|
|
const clock = opts.now ?? (() => new Date())
|
|
const memory = await readCompatible(store)
|
|
|
|
return {
|
|
isFreshCompatible: (host, now) => {
|
|
const last = memory.get(host)
|
|
if (last === undefined) return false
|
|
const elapsed = Math.max(0, (now ?? clock()).getTime() - last)
|
|
return elapsed < ttlMs
|
|
},
|
|
markCompatible: async (host, now) => {
|
|
const stamp = (now ?? clock()).getTime()
|
|
memory.set(host, stamp)
|
|
// Re-read disk inside the write cycle so concurrent processes touching
|
|
// different hosts don't clobber each other's stamps.
|
|
const onDisk = await readCompatible(store)
|
|
onDisk.set(host, stamp)
|
|
await writeCompatible(store, onDisk)
|
|
},
|
|
}
|
|
}
|
|
|
|
async function readCompatible(store: Store): Promise<Map<string, number>> {
|
|
const out = new Map<string, number>()
|
|
let raw: Record<string, string>
|
|
try {
|
|
raw = await store.get(COMPATIBLE_KEY)
|
|
} catch {
|
|
return out
|
|
}
|
|
for (const [host, iso] of Object.entries(raw)) {
|
|
const t = Date.parse(iso)
|
|
if (!Number.isNaN(t)) out.set(host, t)
|
|
}
|
|
return out
|
|
}
|
|
|
|
async function writeCompatible(store: Store, state: Map<string, number>): Promise<void> {
|
|
const compatible: Record<string, string> = {}
|
|
for (const [host, t] of state) compatible[host] = new Date(t).toISOString()
|
|
await store.set(COMPATIBLE_KEY, compatible)
|
|
}
|