Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove caching #11

Merged
merged 2 commits into from
Dec 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions config.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1 @@
extensionModule: ./extension.js
graphqlSchema:
files: '*.graphql'
90 changes: 5 additions & 85 deletions extension.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ import { createRequire } from 'node:module';

import shellQuote from 'shell-quote';

const { NextCache } = databases.cache;

/**
* @typedef {Object} ExtensionOptions - The configuration options for the extension. These are all configurable via `config.yaml`.
* @property {string=} buildCommand - A custom build command. Default to `next build`.
Expand Down Expand Up @@ -287,42 +285,11 @@ export function start(options = {}) {
if (config.subPath && !request._nodeRequest.url.startsWith(`/${config.subPath}/`)) {
return nextHandler(request);
}
const handler = (nodeResponse) => {
// define a handler that will call the Next.js app, that can pass through to the cache resolver function
let nodeRequest = request._nodeRequest;
nodeRequest.url = config.subPath
? nodeRequest.url.replace(new RegExp(`^\/${config.subPath}\/`), '/')
: nodeRequest.url;
return requestHandler(nodeRequest, nodeResponse, url.parse(nodeRequest.url, true));
};
if (config.cache && request.method === 'POST' && request.url === '/invalidate') {
// invalidate the cache
let last;
for await (let entry of NextCache.search([], { onlyIfCached: true, noCacheStore: true })) {
last = NextCache.delete(entry.id);
}
await last;
return { status: 200, headers: {}, body: 'Cache invalidated' };
}
// check if the request is cacheable
if (request.method === 'GET' && config.cache) {
request.handler = handler;
// use our cache table
let response = await NextCache.get(request.url, request);
// if have cache miss, we let the handler actually directly write to the node response object
// and stream the results to the client, so we don't need to return anything here
if (!request._nodeResponse.writableEnded) {
// but if we have a cache hit, we can return the cached response
return {
status: 200,
headers: { ...response.headers.toJSON(), 'X-HarperDB-Cache': 'HIT' },
body: response.content,
};
}
} else {
// else we just let the handler write to the node response object
return handler(request._nodeResponse);
}
let nodeRequest = request._nodeRequest;
nodeRequest.url = config.subPath
? nodeRequest.url.replace(new RegExp(`^\/${config.subPath}\/`), '/')
: nodeRequest.url;
return requestHandler(nodeRequest, request._nodeResponse, url.parse(nodeRequest.url, true));
},
{ port: config.port }
);
Expand All @@ -340,50 +307,3 @@ export function start(options = {}) {
},
};
}

/**
* Source the Next.js cache from request resolution using the passed in Next.js request handler,
* and intercepting the response to cache it.
*/
NextCache.sourcedFrom({
async get(path, context) {
const request = context.requestContext;
return new Promise((resolve, reject) => {
const nodeResponse = request._nodeResponse;
if (!nodeResponse) return;
let cacheable;
// intercept the main methods to get and cache the response
const writeHead = nodeResponse.writeHead;
nodeResponse.writeHead = (status, message, headers) => {
nodeResponse.setHeader('X-HarperDB-Cache', 'MISS');
if (status === 200) cacheable = true;
writeHead.call(nodeResponse, status, message, headers);
};
const blocks = []; // collect the blocks of response data to cache
const write = nodeResponse.write;
nodeResponse.write = (block) => {
if (typeof block === 'string') block = Buffer.from(block);
blocks.push(block);
write.call(nodeResponse, block);
};
const end = nodeResponse.end;
nodeResponse.end = (block) => {
// now we have the full response, cache it
if (block) {
if (typeof block === 'string') block = Buffer.from(block);
blocks.push(block);
}
end.call(nodeResponse, block);
if (!cacheable) context.noCacheStore = true;
// cache the response, with the headers and content
resolve({
id: path,
headers: nodeResponse._headers,
content: blocks.length > 1 ? Buffer.concat(blocks) : blocks[0],
});
};

request.handler(nodeResponse);
});
},
});
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,7 @@
"files": [
"config.yaml",
"extension.js",
"cli.js",
"schema.graphql"
"cli.js"
],
"scripts": {
"format": "prettier .",
Expand Down
5 changes: 0 additions & 5 deletions schema.graphql

This file was deleted.

1 change: 0 additions & 1 deletion util/cache-bust.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ export const MODULE_CACHE_BUST = getCacheBustValue([
'config.yaml',
'cli.js',
'extension.js',
'schema.graphql',
'package.json',
]);

Expand Down
2 changes: 1 addition & 1 deletion util/docker/base.dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ RUN mkdir -p /@harperdb/nextjs
# Cache Bust copying project files
ARG CACHE_BUST
RUN echo "${CACHE_BUST}"
COPY config.yaml extension.js cli.js schema.graphql package.json /@harperdb/nextjs/
COPY config.yaml extension.js cli.js package.json /@harperdb/nextjs/

# Install dependencies for the @harperdb/nextjs module
RUN npm install -C /@harperdb/nextjs
Expand Down
Loading