1
mirror of https://github.com/jakejarvis/jarv.is.git synced 2025-04-26 07:05:21 -04:00

properly use vercel data cache for fetch results

This commit is contained in:
Jake Jarvis 2025-04-04 11:32:20 -04:00
parent f0d4937f0f
commit 68b09ebc36
Signed by: jake
SSH Key Fingerprint: SHA256:nCkvAjYA6XaSPUqc4TfbBQTpzr8Xj7ritg/sGInCdkc
4 changed files with 42 additions and 33 deletions

View File

@ -1,9 +1,7 @@
import { NextResponse } from "next/server"; import { NextResponse } from "next/server";
import { unstable_cache as cache } from "next/cache";
import redis from "../../../lib/helpers/redis"; import redis from "../../../lib/helpers/redis";
export const dynamic = "force-static";
export const revalidate = 1800; // 30 mins
export const GET = async (): Promise< export const GET = async (): Promise<
NextResponse<{ NextResponse<{
total: { total: {
@ -15,32 +13,43 @@ export const GET = async (): Promise<
}>; }>;
}> }>
> => { > => {
// get all keys (aka slugs) const { total, pages } = await cache(
const slugs = await redis.scan(0, { async () => {
match: "hits:*", // get all keys (aka slugs)
type: "string", const slugs = await redis.scan(0, {
// set an arbitrary yet generous upper limit, just in case... match: "hits:*",
count: 99, type: "string",
}); // set an arbitrary yet generous upper limit, just in case...
count: 99,
});
// get the value (number of hits) for each key (the slug of the page) // get the value (number of hits) for each key (the slug of the page)
const values = await redis.mget<string[]>(...slugs[1]); const values = await redis.mget<string[]>(...slugs[1]);
// pair the slugs with their hit values // pair the slugs with their hit values
const pages = slugs[1].map((slug, index) => ({ const pages = slugs[1].map((slug, index) => ({
slug: slug.split(":").pop() as string, // remove the "hits:" prefix slug: slug.split(":").pop() as string, // remove the "hits:" prefix
hits: parseInt(values[index], 10), hits: parseInt(values[index], 10),
})); }));
// sort descending by hits // sort descending by hits
pages.sort((a, b) => b.hits - a.hits); pages.sort((a, b) => b.hits - a.hits);
// calculate total hits // calculate total hits
const total = { hits: 0 }; const total = { hits: 0 };
pages.forEach((page) => { pages.forEach((page) => {
// add these hits to running tally // add these hits to running tally
total.hits += page.hits; total.hits += page.hits;
}); });
return { total, pages };
},
undefined,
{
revalidate: 1800, // 30 minutes
tags: ["hits"],
}
)();
return NextResponse.json({ total, pages }); return NextResponse.json({ total, pages });
}; };

View File

@ -86,8 +86,8 @@ const getRepos = async (): Promise<Project[] | null> => {
...options, ...options,
cache: "force-cache", cache: "force-cache",
next: { next: {
// 10 minutes revalidate: 600, // 10 minutes
revalidate: 600, tags: ["github-api"],
}, },
}); });
}, },

View File

@ -12,8 +12,8 @@ const Gist = async ({ id, file }: GistProps) => {
const scriptResponse = await fetch(scriptUrl, { const scriptResponse = await fetch(scriptUrl, {
cache: "force-cache", cache: "force-cache",
next: { next: {
// cache indefinitely in data store revalidate: false, // cache indefinitely in data store
revalidate: false, tags: ["gist"],
}, },
}); });

View File

@ -1,4 +1,4 @@
import { unstable_cache } from "next/cache"; import { unstable_cache as cache } from "next/cache";
import Image from "next/image"; import Image from "next/image";
import { EmbeddedTweet, TweetNotFound } from "react-tweet"; import { EmbeddedTweet, TweetNotFound } from "react-tweet";
import { fetchTweet as _fetchTweet } from "react-tweet/api"; import { fetchTweet as _fetchTweet } from "react-tweet/api";
@ -12,9 +12,9 @@ export type TweetProps = Omit<ComponentPropsWithoutRef<typeof EmbeddedTweet>, "t
className?: string; className?: string;
}; };
const fetchTweet = unstable_cache(async (id: string) => _fetchTweet(id), [], { const fetchTweet = cache(async (id: string) => _fetchTweet(id), undefined, {
// cache indefinitely revalidate: false, // cache indefinitely
revalidate: false, tags: ["tweet"],
}); });
const Tweet = async ({ id, className, ...rest }: TweetProps) => { const Tweet = async ({ id, className, ...rest }: TweetProps) => {