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

WIP: feat(server/auth): cache auth context results in Redis #3882

Draft
wants to merge 13 commits into
base: main
Choose a base branch
from

Conversation

iainsproat
Copy link
Contributor

@iainsproat iainsproat commented Jan 23, 2025

Description & motivation

Caches the result of the whole auth pipeline in Redis for a configurable amount of time. Defaults to a couple of seconds.

Changes:

  • refactor auth context middleware to incorporate a Redis cache
  • log cache hits, misses, and stores including the request context.
  • refactor error response handling in auth context middleware to make it readable
  • plus; rename rate limiter middleware to use Factory keyword

To-do before merge:

  • test in a testing environment
  • cache log messages do not yet include request ID (should be populated from asyncLocalStorage)
  • delete cache record when tokens are revoked (don't wait until TTL expires)

Screenshots:

Validation of changes:

Logs (read from bottom up):

Showing a cache miss and then the subsequent auth-related database calls and the cache being set before getting to the business-related database calls.

Screenshot 2025-02-06 at 10 21 21

Showing a cache hit, and no auth-related database calls:
Screenshot 2025-02-06 at 10 21 35

Checklist:

  • My pull request follows the guidelines in the Contributing guide?
  • My pull request does not duplicate any other open Pull Requests for the same update/change?
  • My commits are related to the pull request and do not amend unrelated code or documentation.
  • My code follows a similar style to existing code.
  • I have added appropriate tests.
  • I have updated or added relevant documentation.

References

Copy link
Contributor

github-actions bot commented Feb 5, 2025

📸 Preview service has generated an image.

Copy link
Contributor

github-actions bot commented Feb 5, 2025

📸 Preview service has generated an image.

Copy link
Contributor

github-actions bot commented Feb 5, 2025

📸 Preview service has generated an image.

Copy link
Contributor

github-actions bot commented Feb 5, 2025

📸 Preview service has generated an image.

Copy link
Contributor

github-actions bot commented Feb 6, 2025

📸 Preview service has generated an image.

@iainsproat iainsproat requested a review from fabis94 February 18, 2025 11:40
@iainsproat iainsproat changed the title feat(server/auth): cache auth context results in Redis WIP: feat(server/auth): cache auth context results in Redis Feb 18, 2025
Copy link
Contributor

📸 Preview service has generated an image.

}
}): RetrieveFromCache<T> => {
const { options, retrieveFromSource, cache } = deps
const reqLogger = maybeLoggerWithContext({ logger: deps.options.logger })
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know it was created in a different PR, but maybeLoggerWithContext() typing is a bit lacking, as shown in this PR - even tho deps.options.logger is definitely defined, the return type is optional.

That would be fixed through generics:

export const maybeLoggerWithContext = <L extends Optional<Logger>>({ logger }: { logger: L }): L => {
  ...
}

But honestly it's not clear to me why you'd want to return undefined if no logger was passed in anyway. Wouldn't it be better to create a new logger instance, if one wasn't passed in?

req.log = req.log.child({ authContext: loggedContext })
if (!authContext.auth && authContext.err) {
const defaultMessage = 'Unknown Auth context error'
//NOTE due to the possibility of the auth context being rehydrated from cache, we cannot assert the error with `instanceof` and must check the name
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i don't like that it breaks the error in the first place, but also the fact that AuthContext - the TS type - is now conditionally wrong, because if its retrieved from cache the error key most certainly won't be an Error subtype

can we properly rebuild the error, even if its just new Error(oldMessage)? retrieveViaCache() could support a custom formatter, if it doesn't already

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants