Skip to content

Commit 29553f2

Browse files
thesandlordSandeep Dinesh
andauthored
disable local caching for hot reload (#6095)
Co-authored-by: Sandeep Dinesh <[email protected]>
1 parent dece82a commit 29553f2

File tree

2 files changed

+66
-8
lines changed

2 files changed

+66
-8
lines changed

packages/commons/docs-loader/src/kv-cache.ts

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,32 @@ export interface KvCache {
1616
}
1717

1818
/**
19-
* In-memory cache implementation for local development
19+
* No-op cache implementation for local CLI development (fern docs dev)
20+
* This ensures hot reload works by never caching any data
21+
*/
22+
class NoOpKvCache implements KvCache {
23+
async get<T>(_domainKey: string, _key: string, _cacheKeySuffix?: string): Promise<T | null> {
24+
// Never return cached data - always fetch fresh
25+
return null;
26+
}
27+
28+
async mget(_domainKey: string, _keys: string[], _cacheKeySuffix?: string): Promise<Map<string, unknown>> {
29+
// Never return cached data - always fetch fresh
30+
return new Map();
31+
}
32+
33+
set(_domainKey: string, _key: string, _value: unknown, _ttl?: number, _cacheKeySuffix?: string): void {
34+
// Don't cache anything
35+
}
36+
37+
async clear(_domainKey: string): Promise<void> {
38+
// Nothing to clear
39+
}
40+
}
41+
42+
/**
43+
* In-memory cache implementation for local development (pnpm docs:dev in monorepo)
44+
* When isLocal() is true (fern docs dev CLI), all operations are no-ops to enable hot reload
2045
*/
2146
class InMemoryKvCache implements KvCache {
2247
private cache = new Map<string, { value: unknown; expiration?: number }>();
@@ -403,8 +428,20 @@ class UpstashKvCache implements KvCache {
403428

404429
/**
405430
* Factory function to create the appropriate cache implementation
431+
*
432+
* - isLocalDev() = true (fern docs dev CLI): No caching at all for hot reload to work
433+
* - isDocsDev = true (pnpm docs:dev in monorepo): In-memory cache
434+
* - Production: Upstash KV cache
406435
*/
407436
export function createKvCache(isDocsDev: boolean): KvCache {
437+
// For local CLI development (fern docs dev), disable all caching
438+
// This ensures hot reload works by fetching fresh data on every request
439+
// Use local check instead of imported isLocal() to avoid Next.js env var inlining issues
440+
if (isLocal()) {
441+
console.debug("[KvCache] Using no-op cache for local CLI development (hot reload enabled)");
442+
return new NoOpKvCache();
443+
}
444+
// For monorepo docs development (pnpm docs:dev), use in-memory cache
408445
if (isDocsDev) {
409446
console.debug("[KvCache] Using in-memory cache for docs development");
410447
return new InMemoryKvCache();

packages/commons/docs-server/src/loadWithUrl.ts

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,38 @@ setGlobalDispatcher(
2626
);
2727

2828
// In-memory cache for docs dev mode to avoid Next.js 2MB cache limit
29-
const docsDevCache = new Map<string, FdrAPI.docs.v2.read.LoadDocsForUrlResponse>();
29+
// Stores both the response and the timestamp for time-based invalidation
30+
interface CacheEntry {
31+
response: FdrAPI.docs.v2.read.LoadDocsForUrlResponse;
32+
timestamp: number;
33+
}
34+
const docsDevCache = new Map<string, CacheEntry>();
3035
const pendingRequests = new Map<string, Promise<FdrAPI.docs.v2.read.LoadDocsForUrlResponse>>();
3136

37+
// Cache TTL for local development (2 seconds) to allow hot reload while maintaining some caching
38+
const LOCAL_CACHE_TTL_MS = 2000;
39+
3240
export const loadWithUrl = async (domain: string): Promise<FdrAPI.docs.v2.read.LoadDocsForUrlResponse> => {
33-
// In docs dev mode, use in-memory cache instead of unstable_cache
41+
// In docs dev mode (including local CLI), use in-memory cache with time-based invalidation
3442
if (isDocsDev()) {
35-
// Check if we have a cached response
43+
const now = Date.now();
3644
const cached = docsDevCache.get(domain);
45+
46+
// For local CLI development, use shorter TTL for hot reload
47+
const ttl = isLocal() ? LOCAL_CACHE_TTL_MS : Infinity;
48+
49+
// Check if we have a valid cached response (not expired)
50+
if (cached && now - cached.timestamp < ttl) {
51+
console.debug(`[DocsDevCache] Cache hit for domain: ${domain} (age: ${now - cached.timestamp}ms)`);
52+
return cached.response;
53+
}
54+
55+
// If cache is stale, delete it
3756
if (cached) {
38-
console.debug(`[DocsDevCache] Cache hit for domain: ${domain}`);
39-
return cached;
57+
console.debug(
58+
`[DocsDevCache] Cache expired for domain: ${domain} (age: ${now - cached.timestamp}ms, ttl: ${ttl}ms)`
59+
);
60+
docsDevCache.delete(domain);
4061
}
4162

4263
// Check if there's already a pending request for this domain
@@ -51,8 +72,8 @@ export const loadWithUrl = async (domain: string): Promise<FdrAPI.docs.v2.read.L
5172
const requestPromise = (async () => {
5273
try {
5374
const response = await uncachedLoadWithUrl(domain);
54-
// Once resolved, store in cache and remove from pending
55-
docsDevCache.set(domain, response);
75+
// Once resolved, store in cache with timestamp and remove from pending
76+
docsDevCache.set(domain, { response, timestamp: Date.now() });
5677
pendingRequests.delete(domain);
5778
console.debug(`[DocsDevCache] Cached and cleaned up pending request for domain: ${domain}`);
5879
return response;

0 commit comments

Comments
 (0)