added LRU cache to avoid asking firebase to decode the tokens

added prometheus metrics for the token cache
This commit is contained in:
Miodec 2022-09-25 14:48:24 +02:00
parent 61626aa44d
commit a54eb3a3bb
2 changed files with 66 additions and 1 deletions

View file

@ -1,9 +1,44 @@
import admin from "firebase-admin";
import { UserRecord } from "firebase-admin/lib/auth/user-record";
import { DecodedIdToken } from "firebase-admin/lib/auth/token-verifier";
import LRUCache from "lru-cache";
import {
recordTokenCacheAccess,
setTokenCacheLength,
setTokenCacheSize,
} from "./prometheus";
const tokenCache = new LRUCache<string, DecodedIdToken>({
max: 20000,
maxSize: 20000000, // 20MB
sizeCalculation: (token, key): number =>
JSON.stringify(token).length + key.length, //sizeInBytes
});
const TOKEN_CACHE_BUFFER = 1000 * 60 * 5; // 5 minutes
export async function verifyIdToken(idToken: string): Promise<DecodedIdToken> {
return await admin.auth().verifyIdToken(idToken, true);
setTokenCacheLength(tokenCache.size);
setTokenCacheSize(tokenCache.calculatedSize ?? 0);
const cached = tokenCache.get(idToken);
if (cached) {
const expirationDate = (cached.exp - TOKEN_CACHE_BUFFER) * 1000;
if (expirationDate > Date.now()) {
recordTokenCacheAccess("hit_expired");
tokenCache.delete(idToken);
} else {
recordTokenCacheAccess("hit");
return cached;
}
}
recordTokenCacheAccess("miss");
const decoded = await admin.auth().verifyIdToken(idToken, true);
tokenCache.set(idToken, decoded);
return decoded;
}
export async function updateUserEmail(

View file

@ -227,3 +227,33 @@ export function recordRequestCountry(
requestCountry.inc({ path: pathNoGet, country });
}
const tokenCacheAccess = new Counter({
name: "api_token_cache_access",
help: "Token cache access",
labelNames: ["status"],
});
export function recordTokenCacheAccess(
status: "hit" | "miss" | "hit_expired"
): void {
tokenCacheAccess.inc({ status });
}
const tokenCacheSize = new Gauge({
name: "api_token_cache_size",
help: "Token cache size",
});
export function setTokenCacheSize(size: number): void {
tokenCacheSize.set(size);
}
const tokenCacheLength = new Gauge({
name: "api_token_cache_length",
help: "Token cache length",
});
export function setTokenCacheLength(length: number): void {
tokenCacheLength.set(length);
}