forked from mirrored/github-readme-stats
my quick tests for implementing stale-if-error
This commit is contained in:
+20
-3
@@ -7,6 +7,7 @@ import {
|
||||
parseBoolean,
|
||||
renderError,
|
||||
} from "../src/common/utils.js";
|
||||
import { HttpException } from "../src/common/exceptions.js";
|
||||
import { fetchStats } from "../src/fetchers/stats-fetcher.js";
|
||||
import { isLocaleAvailable } from "../src/translations.js";
|
||||
|
||||
@@ -65,7 +66,8 @@ export default async (req, res) => {
|
||||
"Cache-Control",
|
||||
`max-age=${
|
||||
cacheSeconds / 2
|
||||
}, s-maxage=${cacheSeconds}, stale-while-revalidate=${CONSTANTS.ONE_DAY}`,
|
||||
}, s-maxage=${cacheSeconds}, stale-while-revalidate=${CONSTANTS.ONE_DAY},
|
||||
stale-if-error=${CONSTANTS.ONE_HOUR}`,
|
||||
);
|
||||
|
||||
return res.send(
|
||||
@@ -93,12 +95,27 @@ export default async (req, res) => {
|
||||
}),
|
||||
);
|
||||
} catch (err) {
|
||||
// Throw error if REST and GraphQL API calls fail. This way we can return a cached
|
||||
if (err instanceof HttpException) {
|
||||
// throw err;
|
||||
// throw new Error(err.message);
|
||||
// return res.status(404).;
|
||||
// return {statusCode: 404, body: err.message}
|
||||
return res
|
||||
.status(500)
|
||||
.send(
|
||||
renderError(err.errors[0].message, err.errors[0].secondaryMessage),
|
||||
);
|
||||
}
|
||||
|
||||
// Cache the error response less frequently.
|
||||
res.setHeader(
|
||||
"Cache-Control",
|
||||
`max-age=${CONSTANTS.ERROR_CACHE_SECONDS / 2}, s-maxage=${
|
||||
CONSTANTS.ERROR_CACHE_SECONDS
|
||||
}, stale-while-revalidate=${CONSTANTS.ONE_DAY}`,
|
||||
); // Cache the error response less frequently.
|
||||
}, stale-while-revalidate=${CONSTANTS.ONE_DAY}
|
||||
stale-if-error=${CONSTANTS.ONE_HOUR}`,
|
||||
);
|
||||
return res.send(renderError(err.message, err.secondaryMessage));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* @file GRS Exception/Errors.
|
||||
*/
|
||||
|
||||
const SECONDARY_ERROR_MESSAGES = {
|
||||
MAX_RETRY:
|
||||
"Please add an env variable called PAT_1 with your github token in vercel",
|
||||
USER_NOT_FOUND: "Make sure the provided username is not an organization",
|
||||
GRAPHQL_ERROR: "Please try again later",
|
||||
};
|
||||
|
||||
/**
|
||||
* Custom error class to handle custom GRS errors.
|
||||
*
|
||||
* @extends Error
|
||||
*/
|
||||
class CustomError extends Error {
|
||||
/**
|
||||
* @param {string} message Error message.
|
||||
* @param {string} type Error type.
|
||||
*/
|
||||
constructor(message, type) {
|
||||
super(message);
|
||||
this.type = type;
|
||||
this.secondaryMessage = SECONDARY_ERROR_MESSAGES[type] || type;
|
||||
}
|
||||
|
||||
static MAX_RETRY = "MAX_RETRY";
|
||||
static USER_NOT_FOUND = "USER_NOT_FOUND";
|
||||
static GRAPHQL_ERROR = "GRAPHQL_ERROR";
|
||||
}
|
||||
|
||||
/**
|
||||
* Missing query parameter class.
|
||||
*
|
||||
* @extends Error
|
||||
*/
|
||||
class MissingParamError extends Error {
|
||||
/**
|
||||
* @param {string[]} missedParams
|
||||
* @param {string?=} secondaryMessage
|
||||
*/
|
||||
constructor(missedParams, secondaryMessage) {
|
||||
const msg = `Missing params ${missedParams
|
||||
.map((p) => `"${p}"`)
|
||||
.join(", ")} make sure you pass the parameters in URL`;
|
||||
super(msg);
|
||||
this.missedParams = missedParams;
|
||||
this.secondaryMessage = secondaryMessage;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* HttpException class.
|
||||
*
|
||||
* @extends Error
|
||||
*/
|
||||
class HttpException extends Error {
|
||||
/**
|
||||
* Create a HttpException.
|
||||
*
|
||||
* @param {number} statusCode - The status code.
|
||||
* @param {string} message - The error message.
|
||||
* @param {string[]} errors - The errors.
|
||||
*/
|
||||
constructor(
|
||||
statusCode,
|
||||
message = "Exception occurred during the processing of HTTP requests.",
|
||||
errors = [],
|
||||
) {
|
||||
super(message);
|
||||
this.statusCode = statusCode;
|
||||
this.errors = errors;
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
SECONDARY_ERROR_MESSAGES,
|
||||
CustomError,
|
||||
MissingParamError,
|
||||
HttpException,
|
||||
};
|
||||
+1
-2
@@ -21,10 +21,9 @@ export {
|
||||
wrapTextMultiline,
|
||||
logger,
|
||||
CONSTANTS,
|
||||
CustomError,
|
||||
MissingParamError,
|
||||
measureText,
|
||||
lowercaseTrim,
|
||||
chunkArray,
|
||||
parseEmojis,
|
||||
} from "./utils.js";
|
||||
export { CustomError, MissingParamError, HttpException } from "./exceptions.js";
|
||||
|
||||
+12
-3
@@ -1,4 +1,8 @@
|
||||
import { CustomError, logger } from "./utils.js";
|
||||
import { logger } from "./utils.js";
|
||||
import {
|
||||
CustomError,
|
||||
HttpException,
|
||||
} from "./exceptions.js";
|
||||
|
||||
// Script variables.
|
||||
const PATs = Object.keys(process.env).filter((key) =>
|
||||
@@ -16,8 +20,13 @@ const RETRIES = PATs ? PATs : 7;
|
||||
* @returns Promise<retryer>
|
||||
*/
|
||||
const retryer = async (fetcher, variables, retries = 0) => {
|
||||
if (retries > RETRIES) {
|
||||
throw new CustomError("Maximum retries exceeded", CustomError.MAX_RETRY);
|
||||
// if (retries > RETRIES) {
|
||||
if (true) { // FIXME: Test out error
|
||||
throw new HttpException(
|
||||
statusCode=500,
|
||||
message=`Max GraphQL retries exceeded. Please add an env variable called PAT_1 with your github token in vercel.`,
|
||||
errors=[new CustomError("Maximum retries exceeded", CustomError.MAX_RETRY)]
|
||||
);
|
||||
}
|
||||
try {
|
||||
// try to fetch with the first token since RETRIES is 0 index i'm adding +1
|
||||
|
||||
+2
-49
@@ -22,8 +22,7 @@ const renderError = (message, secondaryMessage = "") => {
|
||||
.small { font: 600 12px 'Segoe UI', Ubuntu, Sans-Serif; fill: #252525 }
|
||||
.gray { fill: #858585 }
|
||||
</style>
|
||||
<rect x="0.5" y="0.5" width="${
|
||||
ERROR_CARD_LENGTH - 1
|
||||
<rect x="0.5" y="0.5" width="${ERROR_CARD_LENGTH - 1
|
||||
}" height="99%" rx="4.5" fill="#FFFEFE" stroke="#E4E2E2"/>
|
||||
<text x="25" y="45" class="text">Something went wrong! file an issue at https://tiny.one/readme-stats</text>
|
||||
<text data-testid="message" x="25" y="55" class="text small">
|
||||
@@ -288,7 +287,7 @@ const wrapTextMultiline = (text, width = 59, maxLines = 3) => {
|
||||
return multiLineText;
|
||||
};
|
||||
|
||||
const noop = () => {};
|
||||
const noop = () => { };
|
||||
// return console instance based on the environment
|
||||
const logger =
|
||||
process.env.NODE_ENV !== "test" ? console : { log: noop, error: noop };
|
||||
@@ -310,50 +309,6 @@ const CONSTANTS = {
|
||||
ERROR_CACHE_SECONDS: ERROR_CACHE_SECONDS,
|
||||
};
|
||||
|
||||
const SECONDARY_ERROR_MESSAGES = {
|
||||
MAX_RETRY:
|
||||
"Please add an env variable called PAT_1 with your github token in vercel",
|
||||
USER_NOT_FOUND: "Make sure the provided username is not an organization",
|
||||
GRAPHQL_ERROR: "Please try again later",
|
||||
};
|
||||
|
||||
/**
|
||||
* Custom error class to handle custom GRS errors.
|
||||
*/
|
||||
class CustomError extends Error {
|
||||
/**
|
||||
* @param {string} message Error message.
|
||||
* @param {string} type Error type.
|
||||
*/
|
||||
constructor(message, type) {
|
||||
super(message);
|
||||
this.type = type;
|
||||
this.secondaryMessage = SECONDARY_ERROR_MESSAGES[type] || type;
|
||||
}
|
||||
|
||||
static MAX_RETRY = "MAX_RETRY";
|
||||
static USER_NOT_FOUND = "USER_NOT_FOUND";
|
||||
static GRAPHQL_ERROR = "GRAPHQL_ERROR";
|
||||
}
|
||||
|
||||
/**
|
||||
* Missing query parameter class.
|
||||
*/
|
||||
class MissingParamError extends Error {
|
||||
/**
|
||||
* @param {string[]} missedParams
|
||||
* @param {string?=} secondaryMessage
|
||||
*/
|
||||
constructor(missedParams, secondaryMessage) {
|
||||
const msg = `Missing params ${missedParams
|
||||
.map((p) => `"${p}"`)
|
||||
.join(", ")} make sure you pass the parameters in URL`;
|
||||
super(msg);
|
||||
this.missedParams = missedParams;
|
||||
this.secondaryMessage = secondaryMessage;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve text length.
|
||||
*
|
||||
@@ -451,8 +406,6 @@ export {
|
||||
wrapTextMultiline,
|
||||
logger,
|
||||
CONSTANTS,
|
||||
CustomError,
|
||||
MissingParamError,
|
||||
measureText,
|
||||
lowercaseTrim,
|
||||
chunkArray,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// @ts-check
|
||||
import { retryer } from "../common/retryer.js";
|
||||
import { MissingParamError, request } from "../common/utils.js";
|
||||
import { request } from "../common/utils.js";
|
||||
import { MissingParamError } from "../common/exceptions.js";
|
||||
|
||||
/**
|
||||
* Repo data fetcher.
|
||||
|
||||
@@ -5,12 +5,11 @@ import githubUsernameRegex from "github-username-regex";
|
||||
import { calculateRank } from "../calculateRank.js";
|
||||
import { retryer } from "../common/retryer.js";
|
||||
import {
|
||||
CustomError,
|
||||
logger,
|
||||
MissingParamError,
|
||||
request,
|
||||
wrapTextMultiline,
|
||||
} from "../common/utils.js";
|
||||
import { CustomError, MissingParamError } from "../common/exceptions.js";
|
||||
|
||||
dotenv.config();
|
||||
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
// @ts-check
|
||||
import { retryer } from "../common/retryer.js";
|
||||
import {
|
||||
CustomError,
|
||||
logger,
|
||||
MissingParamError,
|
||||
request,
|
||||
wrapTextMultiline,
|
||||
} from "../common/utils.js";
|
||||
import { CustomError, MissingParamError } from "../common/exceptions.js";
|
||||
|
||||
/**
|
||||
* Top languages fetcher object.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import axios from "axios";
|
||||
import { MissingParamError } from "../common/utils.js";
|
||||
import { MissingParamError } from "../common/exceptions.js";
|
||||
|
||||
/**
|
||||
* WakaTime data fetcher.
|
||||
|
||||
Reference in New Issue
Block a user