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

feat(wip): added cached entity #2489

Merged
merged 44 commits into from
Apr 2, 2023
Merged

feat(wip): added cached entity #2489

merged 44 commits into from
Apr 2, 2023

Conversation

djabarovgeorge
Copy link
Contributor

@djabarovgeorge djabarovgeorge commented Jan 12, 2023

What change does this PR introduce?

It is the POC of dividing the Cached Interceptor into CachedRequest and CachedEntity, this one is the CachedEntity part, I a bit carried away and added a couple of extra queries which were not so necessary at the moment please look at the trigger flow part.

In this solution, we cache under subscriber._id && subscriber.subscriberId separately, and when we need to invalidate we invalidate by key and not by pattern.

Why was this change needed?

In order to reduce the number of scans on the Redis server.

Other information (Screenshots)

@what-the-diff
Copy link

what-the-diff bot commented Jan 13, 2023

  • Added CachedEntity decorator to getSubscriber method in AuthService
  • Changed environmentId parameter name to _environmentId for all methods that use it as a query param (getSubscriber, validateSubscriber)
  • Removed unused imports from SendMessageChat and SendMessageEmail classes
  • Moved GetNovuIntegration class into the same file with other integrations related usecases/classes
  • Added a new interceptor to cache the subscriber entity
  • Updated get-messages usecase to fetch from cache if available
  • Updated create-subscriber and remove-subscriber usecases to invalidate cached entities when creating or removing subscribers respectively
  • Removed CacheKeyPrefixEnum from InvalidateCacheService
  • Added invalidateSubscriber method to InvalidateCacheService
  • Updated all usecases that were using the old clear cache service with new methods and parameters for invalidating subscriber caches (invalidation is now done by id instead of environmentId)
  • Created a CachedEntity interceptor which will fetch an entity based on its type, then store it in request context so other services can access it without having to make another db call or pass around references everywhere

@djabarovgeorge
Copy link
Contributor Author

@scopsy Created caching only by subscriber id.

apps/api/src/app/auth/services/auth.service.ts Outdated Show resolved Hide resolved
Comment on lines 60 to 69
@CachedEntity({
builder: KeyGenerator.subscriber,
})
private async fetchSubscriber({
subscriberId,
_environmentId,
}: {
subscriberId: string;
_environmentId: string;
}): Promise<SubscriberEntity | null> {
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we enforce the param, passed to the function to make sure that it's enforce by TS? That hsubscriberId and environment id is indeed passed?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Tried it about a week ago and a bit struggled to do so.

Comment on lines 62 to 70
const buildQueryKey = ({
type,
keyPrefix,
environmentIdPrefix = 'e',
environmentId,
identifierPrefix = 'i',
identifier,
query,
}: {
Copy link
Contributor

Choose a reason for hiding this comment

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

Would be great to have those unit tested

# Conflicts:
#	.cspell.json
#	apps/api/src/app/events/usecases/process-subscriber/process-subscriber.usecase.ts
#	apps/api/src/app/events/usecases/send-message/send-message-chat.usecase.ts
#	apps/api/src/app/events/usecases/send-message/send-message-email.usecase.ts
#	apps/api/src/app/events/usecases/send-message/send-message-in-app.usecase.ts
#	apps/api/src/app/events/usecases/send-message/send-message-push.usecase.ts
#	apps/api/src/app/events/usecases/send-message/send-message.command.ts
#	apps/api/src/app/events/usecases/send-message/send-message.usecase.ts
#	apps/api/src/app/shared/services/cache/cache.service.ts
#	apps/api/src/app/widgets/usecases/get-notifications-feed/get-notifications-feed.usecase.ts
#	apps/api/src/app/widgets/usecases/mark-all-message-as-seen/mark-all-message-as-seen.usecase.ts
#	apps/api/src/app/widgets/usecases/mark-message-as/mark-message-as.usecase.ts
@ghost
Copy link

ghost commented Jan 29, 2023

👇 Click on the image for a new way to code review
  • Make big changes easier — review code in small groups of related files

  • Know where to start — see the whole change at a glance

  • Take a code tour — explore the change with an interactive tour

  • Make comments and review — all fully sync’ed with github

    Try it now!

Review these changes using an interactive CodeSee Map

Legend

CodeSee Map Legend

@djabarovgeorge
Copy link
Contributor Author

# Conflicts:
#	apps/api/src/app/events/usecases/send-message/send-message-in-app.usecase.ts
#	apps/api/src/app/events/usecases/send-message/send-message.usecase.ts
#	apps/api/src/app/events/usecases/trigger-event/message-matcher.service.spec.ts
#	apps/api/src/app/subscribers/usecases/get-subscriber-template-preference/get-subscriber-template-preference.command.ts
#	apps/api/src/app/subscribers/usecases/get-subscriber-template-preference/get-subscriber-template-preference.usecase.ts
#	apps/api/src/app/subscribers/usecases/update-subscriber-preference/update-subscriber-preference.usecase.ts
Comment on lines 21 to 29
export class KeyGenerator {
public static query = () => {
return { feed, messageCount };
};

public static entity = () => {
return { subscriber, integration, notificationTemplate, user, environmentByApiKey };
};
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This one is a POC I am thinking about what could be the easiest way to interact with the methods, with IDE suggestion of the class methods

}
} catch (err) {
// eslint-disable-next-line no-console
console.error(`An error has occurred when extracting "key: ${methodName}`, 'CacheInterceptor', err);
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
console.error(`An error has occurred when extracting "key: ${methodName}`, 'CacheInterceptor', err);
Logger.error(`An error has occurred when extracting "key: ${methodName}`, 'CacheInterceptor', err);

const variant = this.TTL_VARIANT_PERCENTAGE * num * Math.random();

return Math.floor(num - (this.TTL_VARIANT_PERCENTAGE * num) / 2 + variant);
}

private splitKey(key: string) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Would be great to add test here

@djabarovgeorge djabarovgeorge added this pull request to the merge queue Apr 2, 2023
Merged via the queue into next with commit 2599793 Apr 2, 2023
@djabarovgeorge djabarovgeorge deleted the poc-chached-entity branch April 2, 2023 14:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants