Skip to content

Instantly share code, notes, and snippets.

@tranlehaiquan
Created October 28, 2024 17:39
Show Gist options
  • Save tranlehaiquan/d71fb76981458819ae7fbcc7a9fb5947 to your computer and use it in GitHub Desktop.
Save tranlehaiquan/d71fb76981458819ae7fbcc7a9fb5947 to your computer and use it in GitHub Desktop.
Next.js custom cache-handler.js for GCP Storage
const { CacheHandler } = require('@neshca/cache-handler');
const { Storage } = require('@google-cloud/storage');
const CACHE_PREFIX = 'cache-';
const ENV = process.env.NEXT_ENV || 'dev';
const CACHE_BUCKET_NAME = `your-bucket-${ENV}`;
CacheHandler.onCreation(async (params) => {
const buildId = params.buildId || 'dev';
const storageBucket = CACHE_BUCKET_NAME;
const prefix = CACHE_PREFIX + buildId;
const cacheExtension = 'json';
const gcpStorage = new Storage();
const bucket = gcpStorage.bucket(storageBucket);
const handler = {
async get(key) {
console.log('Getting cache', key);
if (!bucket) {
console.error('Bucket not found');
console.error(CACHE_BUCKET_NAME, GCP_PROJECT_ID);
return null;
}
const contents = await bucket.file(`${prefix}-${key}.${cacheExtension}`).download();
if (!contents) {
return null;
}
console.log('Cache found', key);
return JSON.parse(contents.toString());
},
async set(key, value) {
console.log('Setting cache', key);
const file_key = `${prefix}-${key}.${cacheExtension}`;
const tags = value?.tags;
const expireAt = value.lifespan.expireAt;
const cacheValue = value;
const customMetadata = {
tags: JSON.stringify(tags),
}
await bucket.file(file_key).save(JSON.stringify(cacheValue), {
contentType: 'application/json',
gzip: true,
metadata: {
cacheControl: `max-age=${Math.floor(expireAt - Date.now() / 1000)}`,
contentType: 'application/json',
metadata: customMetadata,
},
});
},
async revalidateTag(tag) {
const [files] = await bucket.getFiles();
const deleteKeys = [];
for (const file of files) {
const [metadata] = await file?.getMetadata();
const fileMetadata = metadata.metadata;
let metaDataTags = [];
if (fileMetadata?.tags && typeof fileMetadata?.tags === 'string') {
metaDataTags = JSON.parse(fileMetadata.tags);
}
if (metaDataTags.includes(tag)) {
deleteKeys.push(file.name);
}
}
await Promise.all(deleteKeys.map((key) => bucket.file(key).delete()));
},
};
return {
handlers: [handler],
};
});
module.exports = CacheHandler;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment