Skip to content

Commit

Permalink
fix caching
Browse files Browse the repository at this point in the history
  • Loading branch information
Razzmatazzz committed Aug 14, 2024
1 parent f403496 commit d8a3f01
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 21 deletions.
6 changes: 4 additions & 2 deletions index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,12 @@ async function graphqlHandler(request, env, ctx) {
specialCache = 'application/json';
}

let key;
// Check the cache service for data first - If cached data exists, return it
// we don't check the cache if we're the http server because the worker already did
if (env.SKIP_CACHE !== 'true' && !env.CLOUDFLARE_TOKEN) {
const cachedResponse = await cacheMachine.get(env, query, variables, specialCache);
key = await cacheMachine.createKey(env, query, variables, specialCache);
const cachedResponse = await cacheMachine.get(env, {key});
if (cachedResponse) {
// Construct a new response with the cached data
const newResponse = new Response(cachedResponse, responseOptions);
Expand Down Expand Up @@ -173,7 +175,7 @@ async function graphqlHandler(request, env, ctx) {

if (env.SKIP_CACHE !== 'true' && ttl > 0) {
// using waitUntil doesn't hold up returning a response but keeps the worker alive as long as needed
ctx.waitUntil(cacheMachine.put(env, body, {query, variables, ttl, specialCache}));
ctx.waitUntil(cacheMachine.put(env, body, {key, query, variables, ttl, specialCache}));
}

return response;
Expand Down
16 changes: 9 additions & 7 deletions plugins/plugin-nightbot.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ const usePaths = [
];

export async function getNightbotResponse(request, url, env, serverContext) {
console.log('serverContext', Object.keys(serverContext));
if (request.method.toUpperCase() !== 'GET') {
return new Response(null, {
status: 405,
Expand All @@ -32,16 +31,19 @@ export async function getNightbotResponse(request, url, env, serverContext) {
const gameMode = url.searchParams.get('m') || 'regular';
const query = url.searchParams.get('q');

if (env.SKIP_CACHE !== 'true') {
let key;
if (env.SKIP_CACHE !== 'true' && !request.headers.has('cache-check-complete')) {
const requestStart = new Date();
const cachedResponse = await cacheMachine.get(env, 'nightbot', { q: query, l: lang, m: gameMode });
key = await cacheMachine.createKey(env, 'nightbot', { q: query, l: lang, m: gameMode });
const cachedResponse = await cacheMachine.get(env, {key});
if (cachedResponse) {
// Construct a new response with the cached data
const newResponse = new Response(cachedResponse);
// Add a custom 'X-CACHE: HIT' header so we know the request hit the cache
newResponse.headers.append('X-CACHE', 'HIT');
console.log(`Request served from cache: ${new Date() - requestStart} ms`);
// Return the new cached response
request.cached = true;
return newResponse;
} else {
console.log('no cached response');
Expand All @@ -57,7 +59,7 @@ export async function getNightbotResponse(request, url, env, serverContext) {
let responseBody = 'Found no item matching that name';
try {
items = await data.worker.item.getItemsByName(context, info, query);
ttl = data.getRequestTtl(context.requestId)
ttl = data.getRequestTtl(context.requestId);

if (items.length > 0) {
const bestPrice = items[0].sellFor.sort((a, b) => b.price - a.price);
Expand All @@ -72,13 +74,13 @@ export async function getNightbotResponse(request, url, env, serverContext) {

// Update the cache with the results of the query
if (env.SKIP_CACHE !== 'true' && ttl > 0) {
const putCachePromise = cacheMachine.put(env, 'nightbot', { q: query, l: lang, m: gameMode }, responseBody, String(ttl));
const putCachePromise = cacheMachine.put(env, responseBody, { key, query: 'nightbot', variables: { q: query, l: lang, m: gameMode }, ttl: String(ttl)});
// using waitUntil doens't hold up returning a response but keeps the worker alive as long as needed
if (request.ctx?.waitUntil) {
request.ctx.waitUntil(putCachePromise);
} /*else if (serverContext.waitUntil) {
} else if (serverContext.waitUntil) {
serverContext.waitUntil(putCachePromise);
}*/
}
}
return new Response(responseBody)
}
Expand Down
25 changes: 22 additions & 3 deletions plugins/plugin-use-cache-machine.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,22 @@ export default function useCacheMachine(env) {
console.log(`Skipping cache check already performed by worker`);
return;
}
const cachedResponse = await cacheMachine.get(env, params.query, params.variables, specialCache(request));
const cachedResponse = await cacheMachine.get(env, {query: params.query, variables: params.variables, specialCache: specialCache(request)});
if (cachedResponse) {
console.log('Request served from cache');
request.cached = true;
setResult(JSON.parse(cachedResponse));
}
},
onValidate({ context, extendContext, params, validateFn, addValidationRule, setValidationFn, setResult }) {
return ({ valid, result, context, extendContext, setResult }) => {
// collect stats on if query was valid
if (valid) {
return;
}
// result is an array of errors we can log
};
},
onContextBuilding({context, extendContext, breakContextBuilding}) {
context.request.ctx = context.ctx ?? context.request.ctx;
if (typeof context.waitUntil === 'function') {
Expand All @@ -40,11 +49,21 @@ export default function useCacheMachine(env) {
console.log(`KVs pre-loaded: ${context.data.kvLoaded.join(', ') || 'none'}`);
extendContext({requestId: context.request.requestId});
},
onExecute({ executeFn, setExecuteFn, setResultAndStopExecution, extendContext, args }) {
const executeStart = new Date();
//extendContext({executeStart: new Date()});
return {
onExecuteDone: ({ args, result, setResult }) => {
console.log(args.contextValue.requestId, `Executaion time: ${new Date() - executeStart} ms`);
// can check for errors at result.errors
},
};
},
onResultProcess({request, acceptableMediaTypes, result, setResult, resultProcessor, setResultProcessor}) {
if (request.cached) {
return;
}
if (!result.data) {
if (!result.data && !result.errors) {
return;
}
if (request.errors?.length > 0) {
Expand All @@ -60,7 +79,7 @@ export default function useCacheMachine(env) {
result.warnings.push(...request.warnings);
}

let ttl = request.data.getRequestTtl(request.requestId);
let ttl = request.data.getRequestTtl(request.requestId) ?? 60 * 5;

const sCache = specialCache(request);
if (sCache === 'application/json') {
Expand Down
24 changes: 15 additions & 9 deletions utils/cache-machine.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ let cachePaused = false;

function pauseCache() {
cacheFailCount++;
if (cacheFailCount <= 2) {
if (cacheFailCount <= 4) {
return;
}
cachePaused = true;
Expand Down Expand Up @@ -39,17 +39,20 @@ async function hash(string) {
}

const cacheMachine = {
createKey: (environment, query, variables, specialCache = '') => {
createKey: (env, query, variables = {}, specialCache = '') => {
if (typeof variables !== 'string') {
variables = JSON.stringify(variables);
}
if (typeof query !== 'string') {
query = JSON.stringify(query);
}
query = query.trim();
return hash(environment + query + variables + specialCache);
return hash(env.ENVIRONMENT + query + variables + specialCache);
},
// Checks the caching service to see if a request has been cached
// :param json: the json payload of the incoming worker request
// :return: json results of the item found in the cache or false if not found
get: async (env, query, variables, specialCache = '') => {
get: async (env, options = {}) => {
try {
if (!env.CACHE_BASIC_AUTH) {
console.warn('env.CACHE_BASIC_AUTH is not set; skipping cache check');
Expand All @@ -59,14 +62,17 @@ const cacheMachine = {
console.warn('Cache paused; skipping cache check');
return false;
}
let query = options.query ?? '';
query = query.trim();
const cacheKey = await cacheMachine.createKey(env.ENVIRONMENT, query, variables, specialCache);
if (!cacheKey) {
let { key, variables = {}, specialCache = '' } = options;
key = key ?? await cacheMachine.createKey(env, query, variables, specialCache);
//console.log('getting cache ', key, typeof query, query);
if (!key) {
console.warn('Skipping cache check; key is empty');
return false;
}

const response = await fetchWithTimeout(`${cacheUrl}/api/cache?key=${cacheKey}`, {
const response = await fetchWithTimeout(`${cacheUrl}/api/cache?key=${key}`, {
headers: {
'content-type': 'application/json;charset=UTF-8',
'Authorization': `Basic ${env.CACHE_BASIC_AUTH}`
Expand Down Expand Up @@ -108,10 +114,10 @@ const cacheMachine = {
console.warn('Key or query not provided, skipping cache put');
return false;
}
let { key, query, variables, ttl = 60, specialCache = '' } = options;
let { key, query, variables, ttl = 60 * 5, specialCache = '' } = options;
if (!key) {
query = query.trim();
key = await cacheMachine.createKey(env.ENVIRONMENT, query, variables, specialCache);
key = await cacheMachine.createKey(env, query, variables, specialCache);
}
ttl = String(ttl);
console.log(`Caching ${body.length} byte response for ${env.ENVIRONMENT} environment${ttl ? ` for ${ttl} seconds` : ''}`);
Expand Down

0 comments on commit d8a3f01

Please sign in to comment.