-
-
Notifications
You must be signed in to change notification settings - Fork 10k
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
Added experimental headers to allow caching members content #20200
Added experimental headers to allow caching members content #20200
Conversation
Currently in a custom build on staging: Staging site: https://cache-members-content-test.ghost.is/ghost/ (owner user info in 1pass) |
6b2162f
to
dbd8afc
Compare
res.setHeader('Set-Cookie', cookiesToSet); | ||
return; | ||
} | ||
const activeSubscription = req.member.subscriptions?.find(sub => sub.status === 'active'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This logic is in two places, which isn't ideal. I'm surprised we don't have an established pattern for "get member's active tier(s)" — surely we'd need this in a lot of different places?
* @param {GetFreeTier} [getFreeTier] - Async function that takes no arguments and resolves to the free tier object. | ||
* @returns {function} Middleware function. | ||
*/ | ||
const getMiddleware = async (getFreeTier = async () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need a way to get the ID of the free tier in the middleware, but for the sake of unit testing I've tried to do a bit of DI here. It works, and it makes testing easier, but I wonder if there is a better way to do this that I've overlooked. Feels a bit overly complicated for what it's doing.
if (shouldCacheMembersContent) { | ||
membersApp.get('/api/member', middleware.loadMemberSession, middleware.accessInfoSession, middleware.getMemberData); | ||
} else { | ||
membersApp.get('/api/member', middleware.getMemberData); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🫣 Would like to refactor this if I have time — feels like this complexity should be in the middleware rather than in the app.
51226f7
to
f835c2d
Compare
ref https://linear.app/tryghost/issue/KTLO-45/deploy-members-caching-solution-to-a-single-site-to-validate-and-test Currently we only cache publicly available content. Any content that is accessed by a logged in member is only cached for that specific member based on their cookie. As a result, almost all requests from logged in members bypass our caching layer and reach Ghost, which adds unnecessary load to Ghost and its database. This change adds experimental headers that allow our CDN to understand which tier to cache the content against, and securely tell the CDN which tier a logged in member has access to. With these changes, we can cache the member content against the tier, rather than the individual member, which should result in a higher cache HIT ratio and reduce the load on Ghost. For requests to the frontend of the site, Ghost will set a custom `X-Member-Cache-Tier` header to the ID of the tier of the member who is accessing the content. This tells the CDN which tier to cache the content against. For requests to either `/members/?token=...` endpoint (the magic link endpoint) or `/members/api/member`, Ghost will set a `ghost-access` and `ghost-access-hmac` cookie with the ID of the tier of the logged in member. With these two pieces of information, our CDN can serve cached content to logged in members. These headers are experimental, and can only be enabled via Ghost's config. To enable these headers, set `cacheMembersContent:enabled` to true and provide an HMAC key in `cacheMembersContent:hmacSecret`.
eccec51
to
cc638b5
Compare
ref https://linear.app/tryghost/issue/KTLO-45/deploy-members-caching-solution-to-a-single-site-to-validate-and-test
Currently we only cache publicly available content. Any content that is accessed by a logged in member is only cached for that specific member based on their cookie. As a result, almost all requests from logged in members bypass our caching layer and reach Ghost, which adds unnecessary load to Ghost and its database.
This change adds experimental headers that allow our CDN to understand which tier to cache the content against, and securely tell the CDN which tier a logged in member has access to. With these changes, we can cache the member content against the tier, rather than the individual member, which should result in a higher cache HIT ratio and reduce the load on Ghost.
For requests to the frontend of the site, Ghost will set a custom
X-Member-Cache-Tier
header to the ID of the tier of the member who is accessing the content. This tells the CDN which tier to cache the content against.For requests to either
/members/?token=...
endpoint (the magic link endpoint) or/members/api/member
, Ghost will set aghost-access
andghost-access-hmac
cookie with the ID of the tier of the logged in member. With these two pieces of information, our CDN can serve cached content to logged in members.These headers are experimental, and can only be enabled via Ghost's config. To enable these headers, set
cacheMembersContent:enabled
totrue
and provide an HMAC key incacheMembersContent:hmacSecret
.