Skip to content

Commit

Permalink
Change frequency
Browse files Browse the repository at this point in the history
  • Loading branch information
stefanoverna committed Dec 2, 2024
1 parent 6944cc0 commit 67d98dd
Show file tree
Hide file tree
Showing 7 changed files with 90 additions and 96 deletions.
2 changes: 1 addition & 1 deletion config/crontab
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
*/10 * * * * curl -i -X POST "https://${DRAFT_MODE_HOSTNAME}/api/memoized-fns-invalidate?token=${SECRET_API_TOKEN}"
0 */6 * * * [ "$DEPLOYMENT_DESTINATION" = "production" ] && curl -i -X PUT -H "Authorization: Bearer ${DATOCMS_API_TOKEN}" -H "Accept: application/json" -H "X-Api-Version: 3" 'https://site-api.datocms.com/build-triggers/34759/reindex'
0 0 * * * [ "$DEPLOYMENT_DESTINATION" = "production" ] && curl -i -X PUT -H "Authorization: Bearer ${DATOCMS_API_TOKEN}" -H "Accept: application/json" -H "X-Api-Version: 3" 'https://site-api.datocms.com/build-triggers/34759/reindex'
19 changes: 2 additions & 17 deletions src/layouts/BaseLayout/Component.astro
Original file line number Diff line number Diff line change
@@ -1,32 +1,17 @@
---
import { TagFragment } from '~/lib/datocms/commonFragments';
import { executeQuery } from '~/lib/datocms/executeQuery';
import { graphql } from '~/lib/datocms/graphql';
import { Seo, type TitleMetaLinkTag } from '@datocms/astro';
import { ViewTransitions } from 'astro:transitions';
import './global.css';
import ProgressBar from './_ProgressBar.astro';
import { fetchFavicon } from './fetchFavicon';
type Props = {
additionalSeo: TitleMetaLinkTag[];
};
const { additionalSeo } = Astro.props;
const query = graphql(
/* GraphQL */ `
query RootQuery {
_site {
faviconMetaTags {
...TagFragment
}
}
}
`,
[TagFragment],
);
const result = await executeQuery(Astro, query);
const [result] = await fetchFavicon(Astro);
---

<!doctype html>
Expand Down
30 changes: 30 additions & 0 deletions src/layouts/BaseLayout/fetchFavicon.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { DATOCMS_API_TOKEN } from 'astro:env/server';
import { dataSource } from '~/lib/dataSource';
import { TagFragment } from '~/lib/datocms/commonFragments';
import { graphql } from '~/lib/datocms/graphql';
import { rawExecuteQueryWithAutoPagination } from '~/lib/datocms/rawExecuteQueryWithAutoPagination';

const query = graphql(
/* GraphQL */ `
query RootQuery {
_site {
faviconMetaTags {
...TagFragment
}
}
}
`,
[TagFragment],
);

export const [fetchFavicon, maybeInvalidateFavicon] = dataSource('favicon', async () => {
const [result, datocmsGraphqlResponse] = await rawExecuteQueryWithAutoPagination(query, {
returnCacheTags: true,
excludeInvalid: true,
token: DATOCMS_API_TOKEN,
});

const cacheTags = datocmsGraphqlResponse.headers.get('x-cache-tags')!.split(' ');

return [result, cacheTags] as const;
});
51 changes: 6 additions & 45 deletions src/lib/dataSource.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import type { AstroGlobal } from 'astro';
import { isEqual, uniq } from 'lodash-es';
import { isEqual } from 'lodash-es';
import { LRUCache } from 'lru-cache';
import { isDraftModeEnabled } from './draftMode';
import { invalidateFastlySurrogateKeys } from './fastly';
import {
augmentResponseHeadersWithSurrogateKeys,
type AstroOrRequestResponseHeaders,
} from './surrogateKeys';

export const cache = new LRUCache({
max: 1000,
Expand All @@ -13,19 +15,12 @@ type MemoizeAndAugumentResponseHeadersFn<T> = (
astroOrRequestResponseHeaders: AstroOrRequestResponseHeaders,
) => Promise<T>;

type AstroOrRequestResponseHeaders =
| AstroGlobal
| {
request: Request;
responseHeaders: Headers;
};

export function dataSource<T>(
surrogateKey: string,
fn: () => Promise<T>,
): [MemoizeAndAugumentResponseHeadersFn<T>, () => Promise<string | false>] {
const queryFn: MemoizeAndAugumentResponseHeadersFn<T> = async (astroOrRequestResponseHeaders) => {
augmentResponseHeadersWithSurrogateKeys(surrogateKey, astroOrRequestResponseHeaders);
augmentResponseHeadersWithSurrogateKeys([surrogateKey], astroOrRequestResponseHeaders);

if (cache.has(surrogateKey)) {
return cache.get(surrogateKey) as T;
Expand Down Expand Up @@ -60,37 +55,3 @@ export function dataSource<T>(

return [queryFn, maybeInvalidateFn];
}

function augmentResponseHeadersWithSurrogateKeys(
surrogateKey: string,
astroOrRequestResponseHeaders: AstroOrRequestResponseHeaders,
) {
const draftModeEnabled = isDraftModeEnabled(
'request' in astroOrRequestResponseHeaders
? astroOrRequestResponseHeaders.request
: astroOrRequestResponseHeaders,
);

const responseHeaders =
'responseHeaders' in astroOrRequestResponseHeaders
? astroOrRequestResponseHeaders.responseHeaders
: astroOrRequestResponseHeaders.response.headers;

const newCacheTags = [surrogateKey];

const surrogateKeyHeaderName = draftModeEnabled ? 'debug-surrogate-key' : 'surrogate-key';
const existingCacheTags = responseHeaders.get(surrogateKeyHeaderName)?.split(' ') ?? [];
const mergedCacheTags = uniq([...existingCacheTags, ...newCacheTags]).join(' ');

responseHeaders.set(surrogateKeyHeaderName, mergedCacheTags);
responseHeaders.set('datocms-cache-tags', mergedCacheTags);

if (draftModeEnabled) {
responseHeaders.set('cache-control', 'private');
} else {
responseHeaders.set(
'surrogate-control',
'max-age=31536000, stale-while-revalidate=60, stale-if-error=86400',
);
}
}
40 changes: 7 additions & 33 deletions src/lib/datocms/executeQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import { type ExecuteQueryOptions as CdaExecuteQueryOptions } from '@datocms/cda
import type { AstroGlobal } from 'astro';
import { DATOCMS_API_TOKEN } from 'astro:env/server';
import type { TadaDocumentNode } from 'gql.tada';
import { uniq } from 'lodash-es';
import { isDraftModeEnabled } from '~/lib/draftMode';
import { augmentResponseHeadersWithSurrogateKeys } from '../surrogateKeys';
import { rawExecuteQueryWithAutoPagination } from './rawExecuteQueryWithAutoPagination';

/**
Expand All @@ -18,15 +18,15 @@ export async function executeQuery<Result, Variables>(
) {
return executeQueryOutsideAstro(query, {
...options,
request: Astro,
request: Astro.request,
responseHeaders: Astro.response.headers,
});
}

export async function executeQueryOutsideAstro<Result, Variables>(
query: TadaDocumentNode<Result, Variables>,
options: Pick<CdaExecuteQueryOptions<Variables>, 'variables'> & {
request: Request | AstroGlobal;
request: Request;
responseHeaders: Headers;
},
) {
Expand All @@ -40,38 +40,12 @@ export async function executeQueryOutsideAstro<Result, Variables>(
token: DATOCMS_API_TOKEN,
});

augmentResponseHeadersWithSurrogateKeys({
draftModeEnabled,
datocmsGraphqlResponse,
const newCacheTags = datocmsGraphqlResponse.headers.get('x-cache-tags')!.split(' ');

augmentResponseHeadersWithSurrogateKeys(newCacheTags, {
request: options.request,
responseHeaders: options.responseHeaders,
});

return result;
}

function augmentResponseHeadersWithSurrogateKeys({
draftModeEnabled,
datocmsGraphqlResponse,
responseHeaders,
}: {
draftModeEnabled: boolean;
datocmsGraphqlResponse: Response;
responseHeaders: Headers;
}) {
const newCacheTags = datocmsGraphqlResponse.headers.get('x-cache-tags')!.split(' ');
const surrogateKeyHeaderName = draftModeEnabled ? 'debug-surrogate-key' : 'surrogate-key';
const existingCacheTags = responseHeaders.get(surrogateKeyHeaderName)?.split(' ') ?? [];
const mergedCacheTags = uniq([...existingCacheTags, ...newCacheTags]).join(' ');

responseHeaders.set(surrogateKeyHeaderName, mergedCacheTags);
responseHeaders.set('datocms-cache-tags', mergedCacheTags);

if (draftModeEnabled) {
responseHeaders.set('cache-control', 'private');
} else {
responseHeaders.set(
'surrogate-control',
'max-age=31536000, stale-while-revalidate=60, stale-if-error=86400',
);
}
}
42 changes: 42 additions & 0 deletions src/lib/surrogateKeys.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import type { AstroGlobal } from 'astro';
import { uniq } from 'lodash-es';
import { isDraftModeEnabled } from './draftMode';

export type AstroOrRequestResponseHeaders =
| AstroGlobal
| {
request: Request;
responseHeaders: Headers;
};

export function augmentResponseHeadersWithSurrogateKeys(
newSurrogateKeys: string[],
astroOrRequestResponseHeaders: AstroOrRequestResponseHeaders,
) {
const draftModeEnabled = isDraftModeEnabled(
'request' in astroOrRequestResponseHeaders
? astroOrRequestResponseHeaders.request
: astroOrRequestResponseHeaders,
);

const responseHeaders =
'responseHeaders' in astroOrRequestResponseHeaders
? astroOrRequestResponseHeaders.responseHeaders
: astroOrRequestResponseHeaders.response.headers;

const surrogateKeyHeaderName = draftModeEnabled ? 'debug-surrogate-key' : 'surrogate-key';
const existingSurrogateKeys = responseHeaders.get(surrogateKeyHeaderName)?.split(' ') ?? [];
const mergedCacheTags = uniq([...existingSurrogateKeys, ...newSurrogateKeys]).join(' ');

responseHeaders.set(surrogateKeyHeaderName, mergedCacheTags);
responseHeaders.set('datocms-cache-tags', mergedCacheTags);

if (draftModeEnabled) {
responseHeaders.set('cache-control', 'private');
} else {
responseHeaders.set(
'surrogate-control',
'max-age=31536000, stale-while-revalidate=60, stale-if-error=86400',
);
}
}
2 changes: 2 additions & 0 deletions src/pages/api/memoized-fns-invalidate/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { maybeInvalidateFetchPluginSdkManifest } from '~/components/docs/blocks/
import { maybeInvalidateReactUiExamples } from '~/components/docs/blocks/ReactUiLiveExample/utils';
import { maybeInvalidateSiteApiHyperschema } from '~/components/docs/restApi/fetchSchema';
import { maybeInvalidateFastlyDatacenters } from '~/components/featureAnimations/CdnMap/utils';
import { maybeInvalidateFavicon } from '~/layouts/BaseLayout/fetchFavicon';
import { maybeInvalidateDastSchema } from '~/pages/docs/structured-text/_utils';
import { maybeInvalidatePerOwnerPricingPlans } from '~/pages/pricing/_sub/perOwnerPricingPlans';
import { handleUnexpectedError, invalidRequestResponse, json } from '../_utils';
Expand All @@ -25,6 +26,7 @@ export const POST: APIRoute = async ({ url, request }) => {
maybeInvalidateReactUiExamples(),
maybeInvalidateDastSchema(),
maybeInvalidateFastlyDatacenters(),
maybeInvalidateFavicon(),
]);

return json({ invalidatedSurrogateKeys: results.filter(Boolean) });
Expand Down

0 comments on commit 67d98dd

Please sign in to comment.