Skip to content

Commit 300cd31

Browse files
chore: redis cache for calendars in api v2 (calcom#23622)
* chore: implement redis cache for calendars api v2 * fixup! chore: implement redis cache for calendars api v2 * fixup! fixup! chore: implement redis cache for calendars api v2 * fix leverage genetic type of redis.get * refactor: address supalarry's PR feedback - Create CalendarsCacheService to separate cache responsibilities - Rename cache methods to be more descriptive (getConnectedAndDestinationCalendarsCache, setConnectedAndDestinationCalendarsCache) - Remove unused redisService injection from CalendarsController - Move all cache-related functionality to dedicated service Addresses comments 9, 10, and 11 from supalarry on PR calcom#23622 Co-Authored-By: morgan@cal.com <morgan@cal.com> * refactor: address supalarry's latest PR feedback - Remove redundant deleteConnectedAndDestinationCalendarsCache from CalendarsService - Update controller to directly inject and use CalendarsCacheService - Extract TTL constant and remove manual JSON.stringify in cache service Co-Authored-By: morgan@cal.com <morgan@cal.com> * fix: update IcsFeedService to use CalendarsCacheService directly - Inject CalendarsCacheService into IcsFeedService constructor - Replace calendarsService.deleteCalendarCache with calendarsCacheService.deleteConnectedAndDestinationCalendarsCache - Completes the refactoring to eliminate all old cache method references Co-Authored-By: morgan@cal.com <morgan@cal.com> * fix: update destination-calendars and selected-calendars services to use CalendarsCacheService directly - Inject CalendarsCacheService in both service constructors - Replace calendarsService.deleteCalendarCache calls with calendarsCacheService.deleteConnectedAndDestinationCalendarsCache - Add CalendarsCacheService to module providers for proper dependency injection - Completes migration of all cache method references to use dedicated cache service Co-Authored-By: morgan@cal.com <morgan@cal.com> * chore: use CalendarsCacheService --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
1 parent f5bb734 commit 300cd31

17 files changed

Lines changed: 205 additions & 21 deletions

File tree

apps/api/v2/src/ee/bookings/2024-04-15/bookings.module.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { BookingsController_2024_04_15 } from "@/ee/bookings/2024-04-15/controllers/bookings.controller";
22
import { PlatformBookingsService } from "@/ee/bookings/shared/platform-bookings.service";
33
import { CalendarsRepository } from "@/ee/calendars/calendars.repository";
4+
import { CalendarsCacheService } from "@/ee/calendars/services/calendars-cache.service";
45
import { CalendarsService } from "@/ee/calendars/services/calendars.service";
56
import { EventTypesModule_2024_04_15 } from "@/ee/event-types/event-types_2024_04_15/event-types.module";
67
import { EventTypesModule_2024_06_14 } from "@/ee/event-types/event-types_2024_06_14/event-types.module";
@@ -41,6 +42,7 @@ import { Module } from "@nestjs/common";
4142
OAuthClientUsersService,
4243
PlatformBookingsService,
4344
CalendarsService,
45+
CalendarsCacheService,
4446
CredentialsRepository,
4547
AppsRepository,
4648
CalendarsRepository,

apps/api/v2/src/ee/bookings/2024-08-13/bookings.module.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { OutputBookingReferencesService_2024_08_13 } from "@/ee/bookings/2024-08
1010
import { OutputBookingsService_2024_08_13 } from "@/ee/bookings/2024-08-13/services/output.service";
1111
import { PlatformBookingsService } from "@/ee/bookings/shared/platform-bookings.service";
1212
import { CalendarsRepository } from "@/ee/calendars/calendars.repository";
13+
import { CalendarsCacheService } from "@/ee/calendars/services/calendars-cache.service";
1314
import { CalendarsService } from "@/ee/calendars/services/calendars.service";
1415
import { EventTypesModule_2024_04_15 } from "@/ee/event-types/event-types_2024_04_15/event-types.module";
1516
import { EventTypesModule_2024_06_14 } from "@/ee/event-types/event-types_2024_06_14/event-types.module";
@@ -71,6 +72,7 @@ import { Module } from "@nestjs/common";
7172
ApiKeysRepository,
7273
PlatformBookingsService,
7374
CalendarsService,
75+
CalendarsCacheService,
7476
CredentialsRepository,
7577
AppsRepository,
7678
CalendarsRepository,

apps/api/v2/src/ee/calendars/calendars.module.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,26 @@ import { BookingsRepository_2024_08_13 } from "@/ee/bookings/2024-08-13/bookings
33
import { CalendarsRepository } from "@/ee/calendars/calendars.repository";
44
import { CalendarsController } from "@/ee/calendars/controllers/calendars.controller";
55
import { AppleCalendarService } from "@/ee/calendars/services/apple-calendar.service";
6+
import { CalendarsCacheService } from "@/ee/calendars/services/calendars-cache.service";
67
import { CalendarsService } from "@/ee/calendars/services/calendars.service";
78
import { GoogleCalendarService } from "@/ee/calendars/services/gcal.service";
89
import { IcsFeedService } from "@/ee/calendars/services/ics-feed.service";
910
import { OutlookService } from "@/ee/calendars/services/outlook.service";
1011
import { AppsRepository } from "@/modules/apps/apps.repository";
1112
import { CredentialsRepository } from "@/modules/credentials/credentials.repository";
1213
import { PrismaModule } from "@/modules/prisma/prisma.module";
14+
import { RedisModule } from "@/modules/redis/redis.module";
1315
import { SelectedCalendarsRepository } from "@/modules/selected-calendars/selected-calendars.repository";
1416
import { TokensModule } from "@/modules/tokens/tokens.module";
1517
import { UsersModule } from "@/modules/users/users.module";
1618
import { Module } from "@nestjs/common";
1719

1820
@Module({
19-
imports: [PrismaModule, UsersModule, TokensModule],
21+
imports: [PrismaModule, UsersModule, TokensModule, RedisModule],
2022
providers: [
2123
CredentialsRepository,
2224
CalendarsService,
25+
CalendarsCacheService,
2326
OutlookService,
2427
GoogleCalendarService,
2528
AppleCalendarService,

apps/api/v2/src/ee/calendars/controllers/calendars.controller.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
DeletedCalendarCredentialsOutputDto,
1010
} from "@/ee/calendars/outputs/delete-calendar-credentials.output";
1111
import { AppleCalendarService } from "@/ee/calendars/services/apple-calendar.service";
12+
import { CalendarsCacheService } from "@/ee/calendars/services/calendars-cache.service";
1213
import { CalendarsService } from "@/ee/calendars/services/calendars.service";
1314
import { GoogleCalendarService } from "@/ee/calendars/services/gcal.service";
1415
import { IcsFeedService } from "@/ee/calendars/services/ics-feed.service";
@@ -79,6 +80,7 @@ const calendarStateSchema = z.object({
7980
export class CalendarsController {
8081
constructor(
8182
private readonly calendarsService: CalendarsService,
83+
private readonly calendarsCacheService: CalendarsCacheService,
8284
private readonly outlookService: OutlookService,
8385
private readonly googleCalendarService: GoogleCalendarService,
8486
private readonly appleCalendarService: AppleCalendarService,
@@ -307,6 +309,8 @@ export class CalendarsController {
307309
credentialId
308310
);
309311

312+
this.calendarsCacheService.deleteConnectedAndDestinationCalendarsCache(user.id);
313+
310314
return {
311315
status: SUCCESS_STATUS,
312316
data: plainToClass(
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { RedisService } from "@/modules/redis/redis.service";
2+
import { Injectable } from "@nestjs/common";
3+
4+
import type { getConnectedDestinationCalendarsAndEnsureDefaultsInDb } from "@calcom/platform-libraries";
5+
6+
export const REDIS_CALENDARS_CACHE_KEY = (userId: number) => `apiv2:user:${userId}:calendars`;
7+
export const CALENDARS_CACHE_TTL_MS = 10_000;
8+
9+
type ConnectedDestinationCalendars = Awaited<
10+
ReturnType<typeof getConnectedDestinationCalendarsAndEnsureDefaultsInDb>
11+
>;
12+
13+
@Injectable()
14+
export class CalendarsCacheService {
15+
constructor(private readonly redisService: RedisService) {}
16+
17+
async deleteConnectedAndDestinationCalendarsCache(userId: number) {
18+
await this.redisService.del(REDIS_CALENDARS_CACHE_KEY(userId));
19+
}
20+
21+
async getConnectedAndDestinationCalendarsCache(userId: number) {
22+
const cachedResult = await this.redisService.get<ConnectedDestinationCalendars>(
23+
REDIS_CALENDARS_CACHE_KEY(userId)
24+
);
25+
return cachedResult;
26+
}
27+
28+
async setConnectedAndDestinationCalendarsCache(
29+
userId: number,
30+
calendars: ConnectedDestinationCalendars
31+
): Promise<void> {
32+
await this.redisService.set<ConnectedDestinationCalendars>(REDIS_CALENDARS_CACHE_KEY(userId), calendars, {
33+
ttl: CALENDARS_CACHE_TTL_MS,
34+
});
35+
}
36+
}

apps/api/v2/src/ee/calendars/services/calendars.service.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { CalendarsRepository } from "@/ee/calendars/calendars.repository";
2+
import { CalendarsCacheService } from "@/ee/calendars/services/calendars-cache.service";
23
import { AppsRepository } from "@/modules/apps/apps.repository";
34
import {
45
CredentialsRepository,
@@ -37,7 +38,8 @@ export class CalendarsService {
3738
private readonly appsRepository: AppsRepository,
3839
private readonly calendarsRepository: CalendarsRepository,
3940
private readonly dbWrite: PrismaWriteService,
40-
private readonly selectedCalendarsRepository: SelectedCalendarsRepository
41+
private readonly selectedCalendarsRepository: SelectedCalendarsRepository,
42+
private readonly calendarsCacheService: CalendarsCacheService
4143
) {}
4244

4345
private buildNonDelegationCredentials<TCredential>(credentials: TCredential[]) {
@@ -52,11 +54,17 @@ export class CalendarsService {
5254
}
5355

5456
async getCalendars(userId: number) {
57+
const cachedResult = await this.calendarsCacheService.getConnectedAndDestinationCalendarsCache(userId);
58+
59+
if (cachedResult) {
60+
return cachedResult;
61+
}
62+
5563
const userWithCalendars = await this.usersRepository.findByIdWithCalendars(userId);
5664
if (!userWithCalendars) {
5765
throw new NotFoundException("User not found");
5866
}
59-
return getConnectedDestinationCalendarsAndEnsureDefaultsInDb({
67+
const result = await getConnectedDestinationCalendarsAndEnsureDefaultsInDb({
6068
user: {
6169
...userWithCalendars,
6270
allSelectedCalendars: userWithCalendars.selectedCalendars,
@@ -68,6 +76,10 @@ export class CalendarsService {
6876
eventTypeId: null,
6977
prisma: this.dbWrite.prisma as unknown as PrismaClient,
7078
});
79+
console.log("saving cache", JSON.stringify(result));
80+
await this.calendarsCacheService.setConnectedAndDestinationCalendarsCache(userId, result);
81+
82+
return result;
7183
}
7284

7385
async getBusyTimes(
@@ -187,6 +199,8 @@ export class CalendarsService {
187199
userId,
188200
calendarType
189201
);
202+
203+
await this.calendarsCacheService.deleteConnectedAndDestinationCalendarsCache(userId);
190204
}
191205

192206
async checkCalendarCredentialValidity(userId: number, credentialId: number, type: string) {

apps/api/v2/src/ee/calendars/services/ics-feed.service.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import { ICSFeedCalendarApp } from "@/ee/calendars/calendars.interface";
22
import { CreateIcsFeedOutputResponseDto } from "@/ee/calendars/input/create-ics.output";
3+
import { CalendarsCacheService } from "@/ee/calendars/services/calendars-cache.service";
34
import { CalendarsService } from "@/ee/calendars/services/calendars.service";
45
import { CredentialsRepository } from "@/modules/credentials/credentials.repository";
6+
import { RedisService } from "@/modules/redis/redis.service";
57
import { BadRequestException, UnauthorizedException, Logger } from "@nestjs/common";
68
import { Injectable } from "@nestjs/common";
79

@@ -13,7 +15,9 @@ import { IcsFeedCalendarService } from "@calcom/platform-libraries/app-store";
1315
export class IcsFeedService implements ICSFeedCalendarApp {
1416
constructor(
1517
private readonly calendarsService: CalendarsService,
16-
private readonly credentialRepository: CredentialsRepository
18+
private readonly calendarsCacheService: CalendarsCacheService,
19+
private readonly credentialRepository: CredentialsRepository,
20+
private readonly redisService: RedisService
1721
) {}
1822

1923
private logger = new Logger("IcsFeedService");
@@ -58,6 +62,9 @@ export class IcsFeedService implements ICSFeedCalendarApp {
5862
data.key,
5963
userId
6064
);
65+
66+
await this.calendarsCacheService.deleteConnectedAndDestinationCalendarsCache(userId);
67+
6168
return {
6269
status: SUCCESS_STATUS,
6370
data: {

apps/api/v2/src/ee/event-types/event-types_2024_06_14/event-types.module.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { CalendarsRepository } from "@/ee/calendars/calendars.repository";
2+
import { CalendarsCacheService } from "@/ee/calendars/services/calendars-cache.service";
23
import { CalendarsService } from "@/ee/calendars/services/calendars.service";
34
import { EventTypesController_2024_06_14 } from "@/ee/event-types/event-types_2024_06_14/controllers/event-types.controller";
45
import { EventTypesRepository_2024_06_14 } from "@/ee/event-types/event-types_2024_06_14/event-types.repository";
@@ -11,14 +12,15 @@ import { AppsRepository } from "@/modules/apps/apps.repository";
1112
import { CredentialsRepository } from "@/modules/credentials/credentials.repository";
1213
import { MembershipsModule } from "@/modules/memberships/memberships.module";
1314
import { PrismaModule } from "@/modules/prisma/prisma.module";
15+
import { RedisModule } from "@/modules/redis/redis.module";
1416
import { SelectedCalendarsModule } from "@/modules/selected-calendars/selected-calendars.module";
1517
import { TokensModule } from "@/modules/tokens/tokens.module";
1618
import { UsersService } from "@/modules/users/services/users.service";
1719
import { UsersRepository } from "@/modules/users/users.repository";
1820
import { Module } from "@nestjs/common";
1921

2022
@Module({
21-
imports: [PrismaModule, MembershipsModule, TokensModule, SelectedCalendarsModule],
23+
imports: [PrismaModule, MembershipsModule, TokensModule, SelectedCalendarsModule, RedisModule],
2224
providers: [
2325
EventTypesRepository_2024_06_14,
2426
EventTypesService_2024_06_14,
@@ -29,6 +31,7 @@ import { Module } from "@nestjs/common";
2931
SchedulesRepository_2024_06_11,
3032
EventTypeResponseTransformPipe,
3133
CalendarsService,
34+
CalendarsCacheService,
3235
CredentialsRepository,
3336
AppsRepository,
3437
CalendarsRepository,

apps/api/v2/src/ee/gcal/gcal.module.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,29 @@
11
import { CalendarsRepository } from "@/ee/calendars/calendars.repository";
2+
import { CalendarsCacheService } from "@/ee/calendars/services/calendars-cache.service";
23
import { CalendarsService } from "@/ee/calendars/services/calendars.service";
34
import { GcalController } from "@/ee/gcal/gcal.controller";
45
import { AppsRepository } from "@/modules/apps/apps.repository";
56
import { GCalService } from "@/modules/apps/services/gcal.service";
67
import { CredentialsRepository } from "@/modules/credentials/credentials.repository";
78
import { OAuthClientModule } from "@/modules/oauth-clients/oauth-client.module";
89
import { PrismaModule } from "@/modules/prisma/prisma.module";
10+
import { RedisModule } from "@/modules/redis/redis.module";
911
import { SelectedCalendarsRepository } from "@/modules/selected-calendars/selected-calendars.repository";
1012
import { TokensModule } from "@/modules/tokens/tokens.module";
1113
import { UsersRepository } from "@/modules/users/users.repository";
1214
import { Module } from "@nestjs/common";
1315
import { ConfigService } from "@nestjs/config";
1416

1517
@Module({
16-
imports: [PrismaModule, TokensModule, OAuthClientModule],
18+
imports: [PrismaModule, TokensModule, OAuthClientModule, RedisModule],
1719
providers: [
1820
AppsRepository,
1921
ConfigService,
2022
CredentialsRepository,
2123
SelectedCalendarsRepository,
2224
GCalService,
2325
CalendarsService,
26+
CalendarsCacheService,
2427
UsersRepository,
2528
CalendarsRepository,
2629
],

apps/api/v2/src/modules/cal-unified-calendars/cal-unified-calendars.module.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { BookingReferencesRepository_2024_08_13 } from "@/ee/bookings/2024-08-13/booking-references.repository";
22
import { CalendarsRepository } from "@/ee/calendars/calendars.repository";
3+
import { CalendarsCacheService } from "@/ee/calendars/services/calendars-cache.service";
34
import { CalendarsService } from "@/ee/calendars/services/calendars.service";
45
import { GoogleCalendarService as GCalService } from "@/ee/calendars/services/gcal.service";
56
import { AppsRepository } from "@/modules/apps/apps.repository";
@@ -8,20 +9,22 @@ import { GoogleCalendarService } from "@/modules/cal-unified-calendars/services/
89
import { CredentialsRepository } from "@/modules/credentials/credentials.repository";
910
import { PrismaReadService } from "@/modules/prisma/prisma-read.service";
1011
import { PrismaWriteService } from "@/modules/prisma/prisma-write.service";
12+
import { RedisModule } from "@/modules/redis/redis.module";
1113
import { SelectedCalendarsRepository } from "@/modules/selected-calendars/selected-calendars.repository";
1214
import { TokensModule } from "@/modules/tokens/tokens.module";
1315
import { UsersRepository } from "@/modules/users/users.repository";
1416
import { Module } from "@nestjs/common";
1517

1618
@Module({
17-
imports: [TokensModule],
19+
imports: [TokensModule, RedisModule],
1820
providers: [
1921
GCalService,
2022
GoogleCalendarService,
2123
AppsRepository,
2224
BookingReferencesRepository_2024_08_13,
2325
CredentialsRepository,
2426
CalendarsService,
27+
CalendarsCacheService,
2528
SelectedCalendarsRepository,
2629
PrismaReadService,
2730
PrismaWriteService,

0 commit comments

Comments
 (0)