Files
dbx/apps/desktop/src/lib/redis/redisAutoRefresh.ts
T

61 lines
2.5 KiB
TypeScript

/**
* Pure decision functions for Redis key auto-refresh countdown.
*
* Extracted from RedisValueViewer.vue to enable unit testing of the
* state-machine logic without mounting a Vue component.
*/
export const MIN_REDIS_AUTO_REFRESH_INTERVAL_SECONDS = 1;
export const MAX_REDIS_AUTO_REFRESH_INTERVAL_SECONDS = 3600;
export const DEFAULT_REDIS_AUTO_REFRESH_INTERVAL_SECONDS = 5;
/** Action computed after evaluating one visible TTL countdown tick. */
export type TtlCountdownTickAction = { type: "idle" } | { type: "decrement" };
/** Keep a user-entered polling frequency within a safe, whole-second range. */
export function normalizeRedisAutoRefreshInterval(value: unknown): number {
const seconds = typeof value === "number" ? value : Number(value);
if (!Number.isFinite(seconds)) return DEFAULT_REDIS_AUTO_REFRESH_INTERVAL_SECONDS;
return Math.min(MAX_REDIS_AUTO_REFRESH_INTERVAL_SECONDS, Math.max(MIN_REDIS_AUTO_REFRESH_INTERVAL_SECONDS, Math.floor(seconds)));
}
/**
* Evaluate one one-second visible TTL countdown tick.
*
* @param countdownTtl Current countdown value in seconds.
* @returns The action the caller should take this tick.
*/
export function computeTtlCountdownTick(countdownTtl: number): TtlCountdownTickAction {
return countdownTtl > 0 ? { type: "decrement" } : { type: "idle" };
}
/** Compute a TTL countdown from the time the server value was observed. */
export function computeTtlCountdownValue(serverTtl: number, observedAtMs: number, nowMs: number): number {
if (serverTtl <= 0) return serverTtl;
const elapsedSeconds = Math.max(0, Math.floor((nowMs - observedAtMs) / 1000));
return Math.max(serverTtl - elapsedSeconds, 0);
}
/**
* Compute the TTL value that should be displayed in the badge.
*
* The local countdown is independent from automatic network refreshes, so the
* last known server TTL must not reappear after the countdown reaches zero.
*/
export function computeDisplayTtl(countdownTtl: number, serverTtl: number): number {
return serverTtl > 0 ? Math.max(countdownTtl, 0) : serverTtl;
}
/**
* Choose the TTL used to initialize an expiry edit.
*
* A zero countdown can be a transient state while the final background refresh
* is still in flight. Do not turn a last-confirmed positive Redis TTL into
* PERSIST during that window.
*/
export function computeTtlForExpiryEdit(countdownTtl: number, serverTtl: number): number {
if (serverTtl <= 0) return serverTtl;
const displayedTtl = computeDisplayTtl(countdownTtl, serverTtl);
return displayedTtl > 0 ? displayedTtl : serverTtl;
}