POC with throttling

This commit is contained in:
George Mandis 2021-11-28 23:55:46 -08:00
parent fb1c48b9a8
commit 87fedd8bda

View file

@ -21,28 +21,45 @@ import chalk from "chalk";
const parser = new Parser(); const parser = new Parser();
const feedList = await getFeedList(); const feedList = await getFeedList();
// calculate the total number of feeds to we can throttle
const feedListLength = Object.entries(feedList).flat(2).length - Object.keys(feedList).length;
const contentFromAllFeeds: Feeds = {}; const contentFromAllFeeds: Feeds = {};
const errors: unknown[] = []; const errors: unknown[] = [];
const allFetches: Promise<boolean | void | undefined>[] = []; const allFetches: Promise<boolean | void | undefined>[] = [];
const MAX_CONNECTIONS = 2;
let connections = 0;
const initTime = Date.now(); const initTime = Date.now();
const benchmark = (startTime: number) => chalk.cyanBright.bold(`(${(Date.now() - startTime) / 1000} seconds)`); const benchmark = (startTime: number) => chalk.cyanBright.bold(`(${(Date.now() - startTime) / 1000} seconds)`);
// used to throttle fetches
const MAX_CONNECTIONS = Infinity;
const DELAY_MS = 850;
const error = chalk.bold.red; const error = chalk.bold.red;
const success = chalk.bold.green; const success = chalk.bold.green;
let completed = 0;
const finishBuild: () => void = async () => {
console.log("\nDone fetching everything!");
// generate the static HTML output from our template renderer
const output = render({
data: contentFromAllFeeds,
errors: errors
});
// write the output to public/index.html
await writeFile("./public/index.html", output);
console.log(`Finished writing to output. ${benchmark(initTime)}`);
};
// process each feed and its content // process each feed and its content
const processFeed = ( const processFeed = (
{ {
group, feed, startTime group, feed, startTime
}: { group: string; feed: string, startTime: number } }: { group: string; feed: string, startTime: number }
) => async (response: Response) => { ) => async (response: Response) => {
connections--;
const body = await parseFeed(response); const body = await parseFeed(response);
completed++;
// skip to the next one if this didn't work out // skip to the next one if this didn't work out
if (!body) return; if (!body) return;
@ -60,50 +77,36 @@ const processFeed = (
item.title = getTitle(item); item.title = getTitle(item);
item.link = getLink(item); item.link = getLink(item);
}); });
contentFromAllFeeds[group].push(contents as object); contentFromAllFeeds[group].push(contents as object);
console.log(`${success("Successfully fetched:")} ${feed} ${benchmark(startTime)}`); console.log(`${success("Successfully fetched:")} ${feed} ${benchmark(startTime)}`);
return true;
} catch (err) { } catch (err) {
console.log(`${error("Error processing:")} ${feed} ${benchmark(startTime)}`); console.log(`${error("Error processing:")} ${feed} ${benchmark(startTime)}`);
errors.push(err); errors.push(err);
return false;
} }
// if this is the last feed, go ahead and build the output
(completed === feedListLength - 1) && finishBuild();
}; };
// go through each group of feeds and process them let idx = 0;
// go through each group of feeds and process
for (const [group, feeds] of Object.entries(feedList)) { for (const [group, feeds] of Object.entries(feedList)) {
contentFromAllFeeds[group] = []; contentFromAllFeeds[group] = [];
for (const feed of feeds) { for (const feed of feeds) {
// throttle if we're exceeding MAX_CONNECTIONS
connections++;
console.log(`Fetching: ${feed}...`);
const startTime = Date.now(); const startTime = Date.now();
allFetches.push( setTimeout(() => {
fetch(feed).then(processFeed({ group, feed, startTime })).catch(err => { console.log(`Fetching: ${feed}...`);
console.log(error(`Error fetching ${feed} ${benchmark(startTime)}`)); allFetches.push(
errors.push(`Error fetching ${feed} ${err.toString()}`); fetch(feed).then(processFeed({ group, feed, startTime })).catch(err => {
}) console.log(error(`Error fetching ${feed} ${benchmark(startTime)}`));
); errors.push(`Error fetching ${feed} ${err.toString()}`);
})
);
}, (idx % (feedListLength / MAX_CONNECTIONS)) * DELAY_MS);
idx++;
} }
} }
// eslint-disable-next-line @typescript-eslint/no-unused-vars
Promise.all(allFetches).then(async () => {
console.log("\nDone fetching everything!");
// generate the static HTML output from our template renderer
const output = render({
data: contentFromAllFeeds,
errors: errors
});
// write the output to public/index.html
await writeFile("./public/index.html", output);
console.log(`Finished writing to output. ${benchmark(initTime)}`);
});