mirror of
https://github.com/System-End/github-readme-stats.git
synced 2026-04-19 21:05:16 +00:00
feat: rate limit error chaching (#2448)
* feat: rate limit error chaching Rate limit error caching to alleviate PATs. * refactor: improve code comments
This commit is contained in:
parent
64f56e88b4
commit
bc8eaecaf4
9 changed files with 54 additions and 18 deletions
|
|
@ -77,7 +77,12 @@ export default async (req, res) => {
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
res.setHeader("Cache-Control", `no-cache, no-store, must-revalidate`); // Don't cache error responses.
|
res.setHeader(
|
||||||
|
"Cache-Control",
|
||||||
|
`max-age=${CONSTANTS.ERROR_CACHE_SECONDS / 2}, s-maxage=${
|
||||||
|
CONSTANTS.ERROR_CACHE_SECONDS
|
||||||
|
}, stale-while-revalidate=${CONSTANTS.ONE_DAY}`,
|
||||||
|
); // Use lower cache period for errors.
|
||||||
return res.send(renderError(err.message, err.secondaryMessage));
|
return res.send(renderError(err.message, err.secondaryMessage));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ export default async (req, res) => {
|
||||||
);
|
);
|
||||||
|
|
||||||
let cacheSeconds = clampValue(
|
let cacheSeconds = clampValue(
|
||||||
parseInt(cache_seconds || CONSTANTS.FOUR_HOURS, 10),
|
parseInt(cache_seconds || CONSTANTS.CARD_CACHE_SECONDS, 10),
|
||||||
CONSTANTS.FOUR_HOURS,
|
CONSTANTS.FOUR_HOURS,
|
||||||
CONSTANTS.ONE_DAY,
|
CONSTANTS.ONE_DAY,
|
||||||
);
|
);
|
||||||
|
|
@ -100,7 +100,12 @@ export default async (req, res) => {
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
res.setHeader("Cache-Control", `no-cache, no-store, must-revalidate`); // Don't cache error responses.
|
res.setHeader(
|
||||||
|
"Cache-Control",
|
||||||
|
`max-age=${CONSTANTS.ERROR_CACHE_SECONDS / 2}, s-maxage=${
|
||||||
|
CONSTANTS.ERROR_CACHE_SECONDS
|
||||||
|
}, stale-while-revalidate=${CONSTANTS.ONE_DAY}`,
|
||||||
|
); // Use lower cache period for errors.
|
||||||
return res.send(renderError(err.message, err.secondaryMessage));
|
return res.send(renderError(err.message, err.secondaryMessage));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ export default async (req, res) => {
|
||||||
const repoData = await fetchRepo(username, repo);
|
const repoData = await fetchRepo(username, repo);
|
||||||
|
|
||||||
let cacheSeconds = clampValue(
|
let cacheSeconds = clampValue(
|
||||||
parseInt(cache_seconds || CONSTANTS.FOUR_HOURS, 10),
|
parseInt(cache_seconds || CONSTANTS.CARD_CACHE_SECONDS, 10),
|
||||||
CONSTANTS.FOUR_HOURS,
|
CONSTANTS.FOUR_HOURS,
|
||||||
CONSTANTS.ONE_DAY,
|
CONSTANTS.ONE_DAY,
|
||||||
);
|
);
|
||||||
|
|
@ -83,7 +83,12 @@ export default async (req, res) => {
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
res.setHeader("Cache-Control", `no-cache, no-store, must-revalidate`); // Don't cache error responses.
|
res.setHeader(
|
||||||
|
"Cache-Control",
|
||||||
|
`max-age=${CONSTANTS.ERROR_CACHE_SECONDS / 2}, s-maxage=${
|
||||||
|
CONSTANTS.ERROR_CACHE_SECONDS
|
||||||
|
}, stale-while-revalidate=${CONSTANTS.ONE_DAY}`,
|
||||||
|
); // Use lower cache period for errors.
|
||||||
return res.send(renderError(err.message, err.secondaryMessage));
|
return res.send(renderError(err.message, err.secondaryMessage));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,7 @@ export default async (req, res) => {
|
||||||
);
|
);
|
||||||
|
|
||||||
let cacheSeconds = clampValue(
|
let cacheSeconds = clampValue(
|
||||||
parseInt(cache_seconds || CONSTANTS.FOUR_HOURS, 10),
|
parseInt(cache_seconds || CONSTANTS.CARD_CACHE_SECONDS, 10),
|
||||||
CONSTANTS.FOUR_HOURS,
|
CONSTANTS.FOUR_HOURS,
|
||||||
CONSTANTS.ONE_DAY,
|
CONSTANTS.ONE_DAY,
|
||||||
);
|
);
|
||||||
|
|
@ -99,7 +99,12 @@ export default async (req, res) => {
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
res.setHeader("Cache-Control", `no-cache, no-store, must-revalidate`); // Don't cache error responses.
|
res.setHeader(
|
||||||
|
"Cache-Control",
|
||||||
|
`max-age=${CONSTANTS.ERROR_CACHE_SECONDS / 2}, s-maxage=${
|
||||||
|
CONSTANTS.ERROR_CACHE_SECONDS
|
||||||
|
}, stale-while-revalidate=${CONSTANTS.ONE_DAY}`,
|
||||||
|
); // Use lower cache period for errors.
|
||||||
return res.send(renderError(err.message, err.secondaryMessage));
|
return res.send(renderError(err.message, err.secondaryMessage));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ export default async (req, res) => {
|
||||||
const stats = await fetchWakatimeStats({ username, api_domain });
|
const stats = await fetchWakatimeStats({ username, api_domain });
|
||||||
|
|
||||||
let cacheSeconds = clampValue(
|
let cacheSeconds = clampValue(
|
||||||
parseInt(cache_seconds || CONSTANTS.FOUR_HOURS, 10),
|
parseInt(cache_seconds || CONSTANTS.CARD_CACHE_SECONDS, 10),
|
||||||
CONSTANTS.FOUR_HOURS,
|
CONSTANTS.FOUR_HOURS,
|
||||||
CONSTANTS.ONE_DAY,
|
CONSTANTS.ONE_DAY,
|
||||||
);
|
);
|
||||||
|
|
@ -50,10 +50,6 @@ export default async (req, res) => {
|
||||||
? parseInt(process.env.CACHE_SECONDS, 10) || cacheSeconds
|
? parseInt(process.env.CACHE_SECONDS, 10) || cacheSeconds
|
||||||
: cacheSeconds;
|
: cacheSeconds;
|
||||||
|
|
||||||
if (!cache_seconds) {
|
|
||||||
cacheSeconds = CONSTANTS.FOUR_HOURS;
|
|
||||||
}
|
|
||||||
|
|
||||||
res.setHeader(
|
res.setHeader(
|
||||||
"Cache-Control",
|
"Cache-Control",
|
||||||
`max-age=${
|
`max-age=${
|
||||||
|
|
@ -82,7 +78,12 @@ export default async (req, res) => {
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
res.setHeader("Cache-Control", `no-cache, no-store, must-revalidate`); // Don't cache error responses.
|
res.setHeader(
|
||||||
|
"Cache-Control",
|
||||||
|
`max-age=${CONSTANTS.ERROR_CACHE_SECONDS / 2}, s-maxage=${
|
||||||
|
CONSTANTS.ERROR_CACHE_SECONDS
|
||||||
|
}, stale-while-revalidate=${CONSTANTS.ONE_DAY}`,
|
||||||
|
); // Use lower cache period for errors.
|
||||||
return res.send(renderError(err.message, err.secondaryMessage));
|
return res.send(renderError(err.message, err.secondaryMessage));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -72,5 +72,5 @@ const retryer = async (fetcher, variables, retries = 0) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export { retryer };
|
export { retryer, RETRIES };
|
||||||
export default retryer;
|
export default retryer;
|
||||||
|
|
|
||||||
|
|
@ -373,11 +373,21 @@ const noop = () => {};
|
||||||
const logger =
|
const logger =
|
||||||
process.env.NODE_ENV !== "test" ? console : { log: noop, error: noop };
|
process.env.NODE_ENV !== "test" ? console : { log: noop, error: noop };
|
||||||
|
|
||||||
|
// Cache settings.
|
||||||
|
const CARD_CACHE_SECONDS = 14400;
|
||||||
|
const ERROR_CACHE_SECONDS = 600;
|
||||||
|
|
||||||
const CONSTANTS = {
|
const CONSTANTS = {
|
||||||
|
ONE_MINUTE: 60,
|
||||||
|
FIVE_MINUTES: 300,
|
||||||
|
TEN_MINUTES: 600,
|
||||||
|
FIFTEEN_MINUTES: 900,
|
||||||
THIRTY_MINUTES: 1800,
|
THIRTY_MINUTES: 1800,
|
||||||
TWO_HOURS: 7200,
|
TWO_HOURS: 7200,
|
||||||
FOUR_HOURS: 14400,
|
FOUR_HOURS: 14400,
|
||||||
ONE_DAY: 86400,
|
ONE_DAY: 86400,
|
||||||
|
CARD_CACHE_SECONDS,
|
||||||
|
ERROR_CACHE_SECONDS,
|
||||||
};
|
};
|
||||||
|
|
||||||
const SECONDARY_ERROR_MESSAGES = {
|
const SECONDARY_ERROR_MESSAGES = {
|
||||||
|
|
|
||||||
|
|
@ -184,13 +184,18 @@ describe("Test /api/", () => {
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should not store cache when error", async () => {
|
it("should set shorter cache when error", async () => {
|
||||||
const { req, res } = faker({}, error);
|
const { req, res } = faker({}, error);
|
||||||
await api(req, res);
|
await api(req, res);
|
||||||
|
|
||||||
expect(res.setHeader.mock.calls).toEqual([
|
expect(res.setHeader.mock.calls).toEqual([
|
||||||
["Content-Type", "image/svg+xml"],
|
["Content-Type", "image/svg+xml"],
|
||||||
["Cache-Control", `no-cache, no-store, must-revalidate`],
|
[
|
||||||
|
"Cache-Control",
|
||||||
|
`max-age=${CONSTANTS.ERROR_CACHE_SECONDS / 2}, s-maxage=${
|
||||||
|
CONSTANTS.ERROR_CACHE_SECONDS
|
||||||
|
}, stale-while-revalidate=${CONSTANTS.ONE_DAY}`,
|
||||||
|
],
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { jest } from "@jest/globals";
|
import { jest } from "@jest/globals";
|
||||||
import "@testing-library/jest-dom";
|
import "@testing-library/jest-dom";
|
||||||
import { retryer } from "../src/common/retryer.js";
|
import { retryer, RETRIES } from "../src/common/retryer.js";
|
||||||
import { logger } from "../src/common/utils.js";
|
import { logger } from "../src/common/utils.js";
|
||||||
import { expect, it, describe } from "@jest/globals";
|
import { expect, it, describe } from "@jest/globals";
|
||||||
|
|
||||||
|
|
@ -44,7 +44,7 @@ describe("Test Retryer", () => {
|
||||||
try {
|
try {
|
||||||
await retryer(fetcherFail, {});
|
await retryer(fetcherFail, {});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
expect(fetcherFail).toBeCalledTimes(8);
|
expect(fetcherFail).toBeCalledTimes(RETRIES + 1);
|
||||||
expect(err.message).toBe("Downtime due to GitHub API rate limiting");
|
expect(err.message).toBe("Downtime due to GitHub API rate limiting");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue