mirror of
https://github.com/GitbookIO/gitbook.git
synced 2026-09-16 23:55:20 +00:00
Fix use of abort controller and parallel lookup of url
This commit is contained in:
+1
-1
@@ -14,7 +14,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@geist-ui/icons": "^1.0.2",
|
||||
"@gitbook/api": "^0.17.0",
|
||||
"@gitbook/api": "^0.20.1",
|
||||
"@radix-ui/react-checkbox": "^1.0.4",
|
||||
"@radix-ui/react-popover": "^1.0.7",
|
||||
"@readme/openapi-parser": "^2.5.0",
|
||||
|
||||
@@ -56,7 +56,6 @@ export const getPublishedContentByUrl = cache(
|
||||
|
||||
// If the request is aborted, we don't need to make the API call
|
||||
// We call it as this logic is wrapped in an asynchronous cache that is not tied to the signal.
|
||||
console.log('getPublishedContentByUrl', signal?.aborted);
|
||||
signal?.throwIfAborted();
|
||||
|
||||
const gitbook = new GitBookAPI({
|
||||
|
||||
+4
-29
@@ -12,7 +12,6 @@ const redis =
|
||||
: null;
|
||||
|
||||
const memoryCache = new Map<string, any>();
|
||||
const pendingOps = new Set<Promise<any>>();
|
||||
|
||||
export interface CacheResult<Result> {
|
||||
data: Result;
|
||||
@@ -76,14 +75,6 @@ export function cacheResponse<Result>(
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for all cache operations to be completed.
|
||||
* This is a workaround until https://github.com/upstash/upstash-redis/issues/778 is fixed.
|
||||
*/
|
||||
export async function waitForCache() {
|
||||
await Promise.all(pendingOps);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a cache key from a function name and its arguments.
|
||||
*/
|
||||
@@ -100,9 +91,7 @@ async function getCacheValue(key: string) {
|
||||
}
|
||||
|
||||
if (redis) {
|
||||
console.log('getCacheValue', key);
|
||||
const value = await wrapOperation(redis.get(key));
|
||||
console.log('done getCacheValue', key);
|
||||
const value = await redis.get(key);
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -116,22 +105,8 @@ async function setCacheValue(key: string, value: any, ttl: number) {
|
||||
memoryCache.set(key, value);
|
||||
|
||||
if (redis) {
|
||||
console.log('setCacheValue', key);
|
||||
await wrapOperation(
|
||||
redis.set(key, value, {
|
||||
ex: ttl,
|
||||
}),
|
||||
);
|
||||
console.log('done setCacheValue', key);
|
||||
await redis.set(key, value, {
|
||||
ex: ttl,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap a cache operation, it can be later awaited with `waitForCache`.
|
||||
*/
|
||||
function wrapOperation<T>(op: Promise<T>): Promise<T> {
|
||||
pendingOps.add(op);
|
||||
return op.finally(() => {
|
||||
pendingOps.delete(op);
|
||||
});
|
||||
}
|
||||
|
||||
+35
-41
@@ -235,57 +235,51 @@ async function lookupSpaceByAPI(
|
||||
} alternatives`,
|
||||
);
|
||||
|
||||
const found = await new Promise<PublishedContentLookup>((resolve, reject) => {
|
||||
let resolved = false;
|
||||
console.time('lookupSpaceByAPI');
|
||||
try {
|
||||
const abort = new AbortController();
|
||||
|
||||
Promise.all(
|
||||
const matches = await Promise.all(
|
||||
lookupAlternatives.map(async (alternative) => {
|
||||
console.log(`lookup content for url "${alternative.url}"`)
|
||||
const data = await getPublishedContentByUrl(
|
||||
alternative.url,
|
||||
apiEndpoint,
|
||||
visitorAuthToken,
|
||||
{
|
||||
signal: abort.signal,
|
||||
},
|
||||
);
|
||||
try {
|
||||
const data = await getPublishedContentByUrl(
|
||||
alternative.url,
|
||||
apiEndpoint,
|
||||
visitorAuthToken,
|
||||
{
|
||||
signal: abort.signal,
|
||||
},
|
||||
);
|
||||
|
||||
if (resolved) {
|
||||
return;
|
||||
}
|
||||
resolved = true;
|
||||
console.log('aborting');
|
||||
abort.abort();
|
||||
if ('redirect' in data) {
|
||||
if (alternative.url === url.toString()) {
|
||||
return data;
|
||||
}
|
||||
|
||||
if (alternative.url === url.toString()) {
|
||||
resolve(data);
|
||||
} else if (!('redirect' in data)) {
|
||||
resolve({
|
||||
return null;
|
||||
}
|
||||
|
||||
// Cancel all other requests to speed up the lookup
|
||||
abort.abort();
|
||||
return {
|
||||
space: data.space,
|
||||
basePath: data.basePath,
|
||||
pathname: joinPath(data.pathname, alternative.extraPath),
|
||||
apiToken: data.apiToken,
|
||||
});
|
||||
} as PublishedContentLookup;
|
||||
} catch (error) {
|
||||
// @ts-ignore
|
||||
if (error.name === 'AbortError') {
|
||||
return null;
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
}),
|
||||
).catch((error) => {
|
||||
if (error.name === 'AbortError') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (resolved) {
|
||||
return;
|
||||
}
|
||||
|
||||
resolved = true;
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
|
||||
await waitForCache();
|
||||
|
||||
return found;
|
||||
);
|
||||
return matches.find((match) => match !== null) ?? null;
|
||||
} finally {
|
||||
console.timeEnd('lookupSpaceByAPI');
|
||||
}
|
||||
}
|
||||
|
||||
function computeLookupAlternatives(url: URL) {
|
||||
|
||||
Reference in New Issue
Block a user