Skip to content

Comments

feat: add framework-agnostic googleapis caching layer to prevent rate limiting#21933

Closed
devin-ai-integration[bot] wants to merge 7 commits intomainfrom
devin/1750376093-googleapis-deduping-layer
Closed

feat: add framework-agnostic googleapis caching layer to prevent rate limiting#21933
devin-ai-integration[bot] wants to merge 7 commits intomainfrom
devin/1750376093-googleapis-deduping-layer

Conversation

@devin-ai-integration
Copy link
Contributor

@devin-ai-integration devin-ai-integration bot commented Jun 20, 2025

Framework-Agnostic Google APIs Caching Layer

🎯 Overview

This PR implements a comprehensive framework-agnostic caching layer for Google Calendar API calls to prevent rate limit quota exhaustion. The solution integrates at the CalendarAuth level to intercept all googleapis calls across both Next.js and Nest.js frameworks without requiring framework detection.

🏗️ Architecture

Core Components

  • GoogleApiCache: Request signature-based caching with configurable time windows (default: 30s)
  • CacheClient Abstraction: Framework-specific implementations
    • EdgeCacheClient: Uses Next.js unstable_cache for server-side caching
    • RedisCacheClient: Leverages existing Redis infrastructure for Nest.js
    • NoOpCacheClient: Fallback for scenarios where caching is disabled
  • CachedCalendarClient: Wrapper for calendar_v3.Calendar with selective caching
  • CachedFetchManager: Central manager for request deduplication

Integration Points

  • CalendarAuth Level: Transparent API call interception without modifying existing flow
  • Explicit Dependency Injection: Cache client type determined at handleNewBooking invocation level
  • No Framework Detection: Manual cache client selection in Next.js API routes and Nest.js modules

🎯 Targeted API Methods

The caching layer focuses on read operations that commonly cause rate limiting:

  • calendar.events.list - Event listing queries
  • calendar.events.get - Individual event retrieval
  • calendar.events.instances - Recurring event instances
  • calendar.freebusy.query - Availability checking
  • calendar.calendarList.list - Calendar enumeration

Write operations (insert, update, delete) bypass caching to prevent data consistency issues.

🔧 Implementation Details

Request Signature Generation

  • SHA-256 hash of method + normalized parameters
  • Removes timestamp-sensitive fields (requestId, quotaUser)
  • Sorts object keys for consistent hashing
  • Per-credential isolation to prevent data leakage

Cache Management

  • Automatic cleanup of expired entries
  • Configurable cache window (default: 30 seconds)
  • Maximum cache size limits (default: 1000 entries per credential)
  • Comprehensive logging for monitoring and debugging

🚀 Integration Examples

Next.js API Route

// apps/web/pages/api/book/event.ts
import { GoogleApiCacheFactory } from "@calcom/app-store/_utils/googleapis";

const cacheClient = GoogleApiCacheFactory.createEdgeCacheClient();
const result = await handleNewBooking({ 
  ...bookingData, 
  cacheClient 
});

Nest.js Module

// apps/api/v2/src/ee/bookings/2024-08-13/bookings.module.ts
@Module({
  providers: [
    {
      provide: 'CACHE_CLIENT',
      useFactory: () => GoogleApiCacheFactory.createRedisCacheClient(),
    },
  ],
})

📊 Benefits

  • Rate Limit Prevention: Eliminates duplicate API calls within configurable time windows
  • Performance Improvement: Cached responses reduce API latency
  • Framework Agnostic: Works identically in Next.js and Nest.js contexts
  • Minimal Disruption: Integrates transparently with existing booking flow
  • Security: Per-credential cache isolation prevents data leakage
  • Monitoring: Comprehensive logging and cache statistics

🧪 Testing

  • Type Safety: All TypeScript compilation passes (yarn type-check:ci)
  • Request Deduplication: Identical API calls within cache window return cached responses
  • Parameter Normalization: Different parameter order produces same cache key
  • Write Operation Bypass: Insert/update/delete operations skip caching
  • Cache Expiration: Entries automatically expire after configured time window

📚 Documentation

Comprehensive documentation included:

  • ARCHITECTURE.md: System design and component relationships
  • INTEGRATION.md: Framework-specific integration guides
  • DEPLOYMENT.md: Production deployment considerations
  • TESTING.md: Testing strategies and verification steps

🔗 Related

  • Addresses rate limiting issues in Google Calendar API integration
  • Complements existing CalendarCache system without interference
  • Maintains compatibility with current OAuthManager and authentication flows

🎉 Link to Devin run

https://app.devin.ai/sessions/37cfda9d9abb43f8a2ee493f50d87417

Requested by: zomars@cal.com


Summary by cubic

Added a framework-agnostic caching layer for Google Calendar API calls to prevent rate limiting, with support for both Next.js and Nest.js through explicit cache client injection.

  • New Features
    • Caches read operations like events.list, events.get, and freebusy.query using a request signature-based cache with a default 30-second window.
    • Integrates at the CalendarAuth level for transparent API call interception without changing existing flows.
    • Supports both Next.js (edge cache) and Nest.js (Redis) environments without framework detection.
    • Includes per-credential cache isolation, automatic cleanup, and detailed logging.
    • Adds documentation and testing guides for integration and deployment.

… limiting

- Implement GoogleApiCache class with configurable cache window and request deduplication
- Create CacheClient abstraction with EdgeCacheClient (Next.js) and RedisCacheClient (Nest.js)
- Add CachedCalendarClient wrapper for calendar_v3.Calendar with selective caching
- Integrate cachedFetch manager at CalendarAuth level for transparent API call interception
- Target calendar.events.*, freebusy.query, calendarList.list methods for caching
- Add explicit dependency injection in both Next.js and Nest.js without framework detection
- Wire up cache client injection at handleNewBooking invocation level to avoid prop-drilling
- Include comprehensive documentation, testing, and deployment guides
- Maintain compatibility with existing CalendarCache and booking flow

Co-Authored-By: zomars@cal.com <zomars@cal.com>
@devin-ai-integration
Copy link
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR that start with 'DevinAI'.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

- Add missing context and acl properties to CachedCalendarClient for Calendar interface compatibility
- Fix iterator compatibility issue in GoogleApiCache using Array.from()
- Replace 'any' types with 'unknown' for better type safety
- Fix unused variable warnings by prefixing with underscore

Co-Authored-By: zomars@cal.com <zomars@cal.com>
@vercel
Copy link

vercel bot commented Jun 20, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

2 Skipped Deployments
Name Status Preview Comments Updated (UTC)
cal-eu ⬜️ Ignored (Inspect) Visit Preview Jun 23, 2025 6:28pm
cal ⬜️ Skipped (Inspect) Jun 23, 2025 6:28pm

- Add proper type assertion for cached response return value (unknown -> T)
- Fix iterator compatibility issue using Array.from() for Map iteration
- All TypeScript compilation errors now resolved locally (yarn type-check:ci passes)

Co-Authored-By: zomars@cal.com <zomars@cal.com>
…port

- Moves GoogleApiCacheService and GoogleApiCacheModule to apps/api/v2/src/modules/googleapis-cache/
- Updates all import statements to use new module location
- Resolves prettier formatting errors with TypeScript decorators
- Fixes 'Cannot find module ./NestJsIntegration' TypeScript compilation errors
- Local yarn type-check:ci passes successfully

Co-Authored-By: zomars@cal.com <zomars@cal.com>
@github-actions
Copy link
Contributor

github-actions bot commented Jun 23, 2025

E2E results are ready!

…ency

- Creates mock provider using NoOpCacheClient for test environments
- Follows existing MockedRedisService pattern for consistency
- Resolves 'Unable to find environment variable: UPSTASH_REDIS_REST_URL' errors
- Ensures E2E tests can run without Redis configuration
- Updates all 14 E2E test files to use the mock provider

Co-Authored-By: zomars@cal.com <zomars@cal.com>
…ider override

- Replace string token with actual class reference in .overrideProvider() calls
- Follows NestJS testing patterns from withApiAuth.ts and withNextAuth.ts
- Resolves Redis dependency injection errors in E2E tests
- Ensures mock provider takes effect during module compilation

Co-Authored-By: zomars@cal.com <zomars@cal.com>
@vercel vercel bot temporarily deployed to Preview – cal June 23, 2025 18:12 Inactive
@vercel vercel bot temporarily deployed to Preview – api June 23, 2025 18:12 Inactive
…compilation errors

- Adds GoogleApiCacheService import to booking-fields.e2e-spec.ts
- Adds GoogleApiCacheService import to api-key-bookings.e2e-spec.ts
- Adds GoogleApiCacheService import to user-emails.e2e-spec.ts
- Resolves 'Cannot find name GoogleApiCacheService' compilation errors
- Ensures all E2E test files can properly override the provider

Co-Authored-By: zomars@cal.com <zomars@cal.com>
@vercel vercel bot temporarily deployed to Preview – api June 23, 2025 18:28 Inactive
@vercel vercel bot temporarily deployed to Preview – cal June 23, 2025 18:28 Inactive
devin-ai-integration bot added a commit that referenced this pull request Jul 1, 2025
- Add framework-agnostic caching system supporting Next.js Edge Cache and Redis
- Implement request signature-based deduplication with 30-second default TTL
- Support read operations (events.list, events.get, freebusy.query, calendarList.list)
- Add per-credential cache isolation for security
- Include comprehensive documentation and testing infrastructure
- Integrate with booking flow through optional dependency injection
- Add NestJS module for Redis cache support in API v2

Based on PR #21933 with updates for main branch compatibility

Co-Authored-By: zomars@cal.com <zomars@me.com>
@devin-ai-integration
Copy link
Contributor Author

Closing due to inactivity for more than 7 days. Configure here.

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.

1 participant