mirror of
https://github.com/GitbookIO/gitbook.git
synced 2026-09-22 18:43:29 +00:00
Merge branch 'main' into stevenh/perf-investigations
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"gitbook-v2": patch
|
||||
---
|
||||
|
||||
Don't cache unexpected API errors for more than a few minutes.
|
||||
@@ -9,7 +9,7 @@ import { getCacheTag, getComputedContentSourceCacheTags } from '@gitbook/cache-t
|
||||
import { GITBOOK_API_TOKEN, GITBOOK_API_URL, GITBOOK_USER_AGENT } from '@v2/lib/env';
|
||||
import { unstable_cacheLife as cacheLife, unstable_cacheTag as cacheTag } from 'next/cache';
|
||||
import { cache } from '../cache';
|
||||
import { DataFetcherError, wrapDataFetcherError } from './errors';
|
||||
import { DataFetcherError, wrapCacheDataFetcherError } from './errors';
|
||||
import type { GitBookDataFetcher } from './types';
|
||||
|
||||
interface DataFetcherInput {
|
||||
@@ -206,8 +206,8 @@ export function createDataFetcher(
|
||||
|
||||
const getUserById = cache(async (input: DataFetcherInput, params: { userId: string }) => {
|
||||
'use cache';
|
||||
return trace(`getUserById(${params.userId})`, async () => {
|
||||
return wrapDataFetcherError(async () => {
|
||||
return wrapCacheDataFetcherError(async () => {
|
||||
return trace(`getUserById(${params.userId})`, async () => {
|
||||
const api = apiClient(input);
|
||||
const res = await api.users.getUserById(params.userId, {
|
||||
...noCacheFetchOptions,
|
||||
@@ -229,8 +229,8 @@ const getSpace = cache(
|
||||
})
|
||||
);
|
||||
|
||||
return trace(`getSpace(${params.spaceId}, ${params.shareKey})`, async () => {
|
||||
return wrapDataFetcherError(async () => {
|
||||
return wrapCacheDataFetcherError(async () => {
|
||||
return trace(`getSpace(${params.spaceId}, ${params.shareKey})`, async () => {
|
||||
const api = apiClient(input);
|
||||
const res = await api.spaces.getSpaceById(
|
||||
params.spaceId,
|
||||
@@ -260,20 +260,23 @@ const getChangeRequest = cache(
|
||||
})
|
||||
);
|
||||
|
||||
return trace(`getChangeRequest(${params.spaceId}, ${params.changeRequestId})`, async () => {
|
||||
return wrapDataFetcherError(async () => {
|
||||
const api = apiClient(input);
|
||||
const res = await api.spaces.getChangeRequestById(
|
||||
params.spaceId,
|
||||
params.changeRequestId,
|
||||
{
|
||||
...noCacheFetchOptions,
|
||||
}
|
||||
);
|
||||
cacheTag(...getCacheTagsFromResponse(res));
|
||||
cacheLife('minutes');
|
||||
return res.data;
|
||||
});
|
||||
return wrapCacheDataFetcherError(async () => {
|
||||
return trace(
|
||||
`getChangeRequest(${params.spaceId}, ${params.changeRequestId})`,
|
||||
async () => {
|
||||
const api = apiClient(input);
|
||||
const res = await api.spaces.getChangeRequestById(
|
||||
params.spaceId,
|
||||
params.changeRequestId,
|
||||
{
|
||||
...noCacheFetchOptions,
|
||||
}
|
||||
);
|
||||
cacheTag(...getCacheTagsFromResponse(res));
|
||||
cacheLife('minutes');
|
||||
return res.data;
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
);
|
||||
@@ -284,8 +287,8 @@ const getRevision = cache(
|
||||
params: { spaceId: string; revisionId: string; metadata: boolean }
|
||||
) => {
|
||||
'use cache';
|
||||
return trace(`getRevision(${params.spaceId}, ${params.revisionId})`, async () => {
|
||||
return wrapDataFetcherError(async () => {
|
||||
return wrapCacheDataFetcherError(async () => {
|
||||
return trace(`getRevision(${params.spaceId}, ${params.revisionId})`, async () => {
|
||||
const api = apiClient(input);
|
||||
const res = await api.spaces.getRevisionById(
|
||||
params.spaceId,
|
||||
@@ -311,8 +314,8 @@ const getRevisionPages = cache(
|
||||
params: { spaceId: string; revisionId: string; metadata: boolean }
|
||||
) => {
|
||||
'use cache';
|
||||
return trace(`getRevisionPages(${params.spaceId}, ${params.revisionId})`, async () => {
|
||||
return wrapDataFetcherError(async () => {
|
||||
return wrapCacheDataFetcherError(async () => {
|
||||
return trace(`getRevisionPages(${params.spaceId}, ${params.revisionId})`, async () => {
|
||||
const api = apiClient(input);
|
||||
const res = await api.spaces.listPagesInRevisionById(
|
||||
params.spaceId,
|
||||
@@ -338,10 +341,10 @@ const getRevisionFile = cache(
|
||||
params: { spaceId: string; revisionId: string; fileId: string }
|
||||
) => {
|
||||
'use cache';
|
||||
return trace(
|
||||
`getRevisionFile(${params.spaceId}, ${params.revisionId}, ${params.fileId})`,
|
||||
async () => {
|
||||
return wrapDataFetcherError(async () => {
|
||||
return wrapCacheDataFetcherError(async () => {
|
||||
return trace(
|
||||
`getRevisionFile(${params.spaceId}, ${params.revisionId}, ${params.fileId})`,
|
||||
async () => {
|
||||
const api = apiClient(input);
|
||||
const res = await api.spaces.getFileInRevisionById(
|
||||
params.spaceId,
|
||||
@@ -355,9 +358,9 @@ const getRevisionFile = cache(
|
||||
cacheTag(...getCacheTagsFromResponse(res));
|
||||
cacheLife('max');
|
||||
return res.data;
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
@@ -367,10 +370,10 @@ const getRevisionPageMarkdown = cache(
|
||||
params: { spaceId: string; revisionId: string; pageId: string }
|
||||
) => {
|
||||
'use cache';
|
||||
return trace(
|
||||
`getRevisionPageMarkdown(${params.spaceId}, ${params.revisionId}, ${params.pageId})`,
|
||||
async () => {
|
||||
return wrapDataFetcherError(async () => {
|
||||
return wrapCacheDataFetcherError(async () => {
|
||||
return trace(
|
||||
`getRevisionPageMarkdown(${params.spaceId}, ${params.revisionId}, ${params.pageId})`,
|
||||
async () => {
|
||||
const api = apiClient(input);
|
||||
const res = await api.spaces.getPageInRevisionById(
|
||||
params.spaceId,
|
||||
@@ -391,9 +394,9 @@ const getRevisionPageMarkdown = cache(
|
||||
throw new DataFetcherError('Page is not a document', 404);
|
||||
}
|
||||
return res.data.markdown;
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
@@ -403,10 +406,10 @@ const getRevisionPageDocument = cache(
|
||||
params: { spaceId: string; revisionId: string; pageId: string }
|
||||
) => {
|
||||
'use cache';
|
||||
return trace(
|
||||
`getRevisionPageDocument(${params.spaceId}, ${params.revisionId}, ${params.pageId})`,
|
||||
async () => {
|
||||
return wrapDataFetcherError(async () => {
|
||||
return wrapCacheDataFetcherError(async () => {
|
||||
return trace(
|
||||
`getRevisionPageDocument(${params.spaceId}, ${params.revisionId}, ${params.pageId})`,
|
||||
async () => {
|
||||
const api = apiClient(input);
|
||||
const res = await api.spaces.getPageDocumentInRevisionById(
|
||||
params.spaceId,
|
||||
@@ -424,9 +427,9 @@ const getRevisionPageDocument = cache(
|
||||
cacheLife('max');
|
||||
|
||||
return res.data;
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
@@ -436,11 +439,11 @@ const getRevisionPageByPath = cache(
|
||||
params: { spaceId: string; revisionId: string; path: string }
|
||||
) => {
|
||||
'use cache';
|
||||
return trace(
|
||||
`getRevisionPageByPath(${params.spaceId}, ${params.revisionId}, ${params.path})`,
|
||||
async () => {
|
||||
const encodedPath = encodeURIComponent(params.path);
|
||||
return wrapDataFetcherError(async () => {
|
||||
return wrapCacheDataFetcherError(async () => {
|
||||
return trace(
|
||||
`getRevisionPageByPath(${params.spaceId}, ${params.revisionId}, ${params.path})`,
|
||||
async () => {
|
||||
const encodedPath = encodeURIComponent(params.path);
|
||||
const api = apiClient(input);
|
||||
const res = await api.spaces.getPageInRevisionByPath(
|
||||
params.spaceId,
|
||||
@@ -454,17 +457,17 @@ const getRevisionPageByPath = cache(
|
||||
cacheTag(...getCacheTagsFromResponse(res));
|
||||
cacheLife('max');
|
||||
return res.data;
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
const getDocument = cache(
|
||||
async (input: DataFetcherInput, params: { spaceId: string; documentId: string }) => {
|
||||
'use cache';
|
||||
return trace(`getDocument(${params.spaceId}, ${params.documentId})`, async () => {
|
||||
return wrapDataFetcherError(async () => {
|
||||
return wrapCacheDataFetcherError(async () => {
|
||||
return trace(`getDocument(${params.spaceId}, ${params.documentId})`, async () => {
|
||||
const api = apiClient(input);
|
||||
const res = await api.spaces.getDocumentById(
|
||||
params.spaceId,
|
||||
@@ -503,10 +506,10 @@ const getComputedDocument = cache(
|
||||
)
|
||||
);
|
||||
|
||||
return trace(
|
||||
`getComputedDocument(${params.spaceId}, ${params.organizationId}, ${params.source.type}, ${params.seed})`,
|
||||
async () => {
|
||||
return wrapDataFetcherError(async () => {
|
||||
return wrapCacheDataFetcherError(async () => {
|
||||
return trace(
|
||||
`getComputedDocument(${params.spaceId}, ${params.organizationId}, ${params.source.type}, ${params.seed})`,
|
||||
async () => {
|
||||
const api = apiClient(input);
|
||||
const res = await api.spaces.getComputedDocument(
|
||||
params.spaceId,
|
||||
@@ -522,9 +525,9 @@ const getComputedDocument = cache(
|
||||
cacheTag(...getCacheTagsFromResponse(res));
|
||||
cacheLife('max');
|
||||
return res.data;
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
@@ -534,10 +537,10 @@ const getReusableContent = cache(
|
||||
params: { spaceId: string; revisionId: string; reusableContentId: string }
|
||||
) => {
|
||||
'use cache';
|
||||
return trace(
|
||||
`getReusableContent(${params.spaceId}, ${params.revisionId}, ${params.reusableContentId})`,
|
||||
async () => {
|
||||
return wrapDataFetcherError(async () => {
|
||||
return wrapCacheDataFetcherError(async () => {
|
||||
return trace(
|
||||
`getReusableContent(${params.spaceId}, ${params.revisionId}, ${params.reusableContentId})`,
|
||||
async () => {
|
||||
const api = apiClient(input);
|
||||
const res = await api.spaces.getReusableContentInRevisionById(
|
||||
params.spaceId,
|
||||
@@ -551,9 +554,9 @@ const getReusableContent = cache(
|
||||
cacheTag(...getCacheTagsFromResponse(res));
|
||||
cacheLife('max');
|
||||
return res.data;
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
@@ -568,10 +571,10 @@ const getLatestOpenAPISpecVersionContent = cache(
|
||||
})
|
||||
);
|
||||
|
||||
return trace(
|
||||
`getLatestOpenAPISpecVersionContent(${params.organizationId}, ${params.slug})`,
|
||||
async () => {
|
||||
return wrapDataFetcherError(async () => {
|
||||
return wrapCacheDataFetcherError(async () => {
|
||||
return trace(
|
||||
`getLatestOpenAPISpecVersionContent(${params.organizationId}, ${params.slug})`,
|
||||
async () => {
|
||||
const api = apiClient(input);
|
||||
const res = await api.orgs.getLatestOpenApiSpecVersionContent(
|
||||
params.organizationId,
|
||||
@@ -583,9 +586,9 @@ const getLatestOpenAPISpecVersionContent = cache(
|
||||
cacheTag(...getCacheTagsFromResponse(res));
|
||||
cacheLife('max');
|
||||
return res.data;
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
@@ -602,10 +605,10 @@ const getPublishedContentSite = cache(
|
||||
})
|
||||
);
|
||||
|
||||
return trace(
|
||||
`getPublishedContentSite(${params.organizationId}, ${params.siteId}, ${params.siteShareKey})`,
|
||||
async () => {
|
||||
return wrapDataFetcherError(async () => {
|
||||
return wrapCacheDataFetcherError(async () => {
|
||||
return trace(
|
||||
`getPublishedContentSite(${params.organizationId}, ${params.siteId}, ${params.siteShareKey})`,
|
||||
async () => {
|
||||
const api = apiClient(input);
|
||||
const res = await api.orgs.getPublishedContentSite(
|
||||
params.organizationId,
|
||||
@@ -620,9 +623,9 @@ const getPublishedContentSite = cache(
|
||||
cacheTag(...getCacheTagsFromResponse(res));
|
||||
cacheLife('days');
|
||||
return res.data;
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
@@ -644,10 +647,10 @@ const getSiteRedirectBySource = cache(
|
||||
})
|
||||
);
|
||||
|
||||
return trace(
|
||||
`getSiteRedirectBySource(${params.organizationId}, ${params.siteId}, ${params.siteShareKey}, ${params.source})`,
|
||||
async () => {
|
||||
return wrapDataFetcherError(async () => {
|
||||
return wrapCacheDataFetcherError(async () => {
|
||||
return trace(
|
||||
`getSiteRedirectBySource(${params.organizationId}, ${params.siteId}, ${params.siteShareKey}, ${params.source})`,
|
||||
async () => {
|
||||
const api = apiClient(input);
|
||||
const res = await api.orgs.getSiteRedirectBySource(
|
||||
params.organizationId,
|
||||
@@ -663,9 +666,9 @@ const getSiteRedirectBySource = cache(
|
||||
cacheTag(...getCacheTagsFromResponse(res));
|
||||
cacheLife('days');
|
||||
return res.data;
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
@@ -679,8 +682,8 @@ const getEmbedByUrl = cache(
|
||||
})
|
||||
);
|
||||
|
||||
return trace(`getEmbedByUrl(${params.spaceId}, ${params.url})`, async () => {
|
||||
return wrapDataFetcherError(async () => {
|
||||
return wrapCacheDataFetcherError(async () => {
|
||||
return trace(`getEmbedByUrl(${params.spaceId}, ${params.url})`, async () => {
|
||||
const api = apiClient(input);
|
||||
const res = await api.spaces.getEmbedByUrlInSpace(
|
||||
params.spaceId,
|
||||
@@ -712,10 +715,10 @@ const searchSiteContent = cache(
|
||||
})
|
||||
);
|
||||
|
||||
return trace(
|
||||
`searchSiteContent(${params.organizationId}, ${params.siteId}, ${params.query})`,
|
||||
async () => {
|
||||
return wrapDataFetcherError(async () => {
|
||||
return wrapCacheDataFetcherError(async () => {
|
||||
return trace(
|
||||
`searchSiteContent(${params.organizationId}, ${params.siteId}, ${params.query})`,
|
||||
async () => {
|
||||
const { organizationId, siteId, query, scope } = params;
|
||||
const api = apiClient(input);
|
||||
const res = await api.orgs.searchSiteContent(
|
||||
@@ -733,9 +736,9 @@ const searchSiteContent = cache(
|
||||
cacheTag(...getCacheTagsFromResponse(res));
|
||||
cacheLife('hours');
|
||||
return res.data.items;
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
@@ -752,8 +755,8 @@ const renderIntegrationUi = cache(
|
||||
})
|
||||
);
|
||||
|
||||
return trace(`renderIntegrationUi(${params.integrationName})`, async () => {
|
||||
return wrapDataFetcherError(async () => {
|
||||
return wrapCacheDataFetcherError(async () => {
|
||||
return trace(`renderIntegrationUi(${params.integrationName})`, async () => {
|
||||
const api = apiClient(input);
|
||||
const res = await api.integrations.renderIntegrationUiWithPost(
|
||||
params.integrationName,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { GitBookAPIError } from '@gitbook/api';
|
||||
import { unstable_cacheLife as cacheLife } from 'next/cache';
|
||||
import type { DataFetcherErrorData, DataFetcherResponse } from './types';
|
||||
|
||||
export class DataFetcherError extends Error {
|
||||
@@ -89,6 +90,22 @@ export async function wrapDataFetcherError<T>(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap an async execution to handle errors and return a DataFetcherResponse.
|
||||
* This should be used inside 'use cache' functions.
|
||||
*/
|
||||
export async function wrapCacheDataFetcherError<T>(
|
||||
fn: () => Promise<T>
|
||||
): Promise<DataFetcherResponse<T>> {
|
||||
const result = await wrapDataFetcherError(fn);
|
||||
if (result.error && result.error.code >= 500) {
|
||||
// We don't want to cache errors for too long.
|
||||
// as the API might
|
||||
cacheLife('minutes');
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ignore some data fetcher errors.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user