veza/apps/web/docs/REQUEST_DEDUPLICATION_AUDIT.md
senke 7123102411 data-flow: audit request deduplication utility
- Completed Action 2.5.1.1: Audited requestDeduplication utility
- Created REQUEST_DEDUPLICATION_AUDIT.md with complete analysis
- Verified core functionality: promise sharing, key generation, cleanup
- Documented usage patterns via deduplicatedApiClient
- Identified potential issues: FormData handling, unbounded cache size
- Noted utility may not be actively used (needs verification)
- Provided recommendations for improvements and testing
2026-01-11 16:44:05 +01:00

5.2 KiB

Request Deduplication Utility Audit

Date: 2025-01-27
Action: 2.5.1.1 - Audit requestDeduplication utility
Status: Complete

Overview

This document audits the requestDeduplication utility to verify it works correctly and documents its usage.

File Location

  • Source: apps/web/src/services/requestDeduplication.ts
  • Exports: requestDeduplication (singleton instance)
  • Usage: Via deduplicatedApiClient in apps/web/src/services/api/client.ts

Implementation Analysis

Core Functionality

The utility prevents duplicate API calls by sharing the same promise for identical concurrent requests.

Key Features:

  1. Request Key Generation: Creates unique keys from method, URL, params, and body
  2. Promise Sharing: Identical concurrent requests share the same promise
  3. Automatic Cleanup: Removes completed requests from cache after 1 second
  4. Periodic Cleanup: Removes stale entries older than 1 minute every 5 minutes

Request Key Generation

Method: generateRequestKey(config: AxiosRequestConfig): string

Key Components:

  • HTTP method (uppercase)
  • Full URL (baseURL + url)
  • Sorted query parameters (JSON stringified)
  • Request body (JSON stringified, or [FormData] flag)

Example Key: GET:http://localhost:8080/api/v1/tracks?page=1&limit=10

Limitations:

  • FormData requests use [FormData] flag (cannot serialize binary data)
  • May deduplicate different FormData requests incorrectly

Deduplication Logic

Method: shouldDeduplicate(config: AxiosRequestConfig): boolean

Rules:

  • Always deduplicate: GET, HEAD, OPTIONS requests
  • ⚠️ Mutations (POST, PUT, DELETE, PATCH): Only if _enableDeduplication !== false
  • Never deduplicate: If _disableDeduplication === true

Safety: Mutations are NOT deduplicated by default (prevents accidental deduplication of different POST requests)

Cache Management

Cache Structure:

interface CachedRequest {
  promise: Promise<any>;
  timestamp: number;
  resolveCount: number; // Tracks how many requests share this promise
}

Cache Lifecycle:

  1. Request starts → Added to cache
  2. Request completes → Kept in cache for 1 second (default)
  3. After 1 second → Removed from cache
  4. On error → Immediately removed from cache
  5. Periodic cleanup → Removes entries older than 1 minute

Cache Size: No explicit limit (unbounded, but cleaned periodically)

Usage Pattern

Via deduplicatedApiClient:

// Multiple identical requests share the same promise
const promise1 = deduplicatedApiClient.get('/tracks');
const promise2 = deduplicatedApiClient.get('/tracks');
// promise1 === promise2 (same promise instance)

Direct Usage:

import { requestDeduplication } from '@/services/requestDeduplication';

const result = await requestDeduplication.getOrCreateRequest(
  config,
  () => apiClient.get('/tracks'),
  { enabled: true, cacheTime: 1000 }
);

Integration Points

API Client Integration

Location: apps/web/src/services/api/client.ts:1146-1190

Exported as: deduplicatedApiClient object with methods:

  • get<T>(url, config?)
  • post<T>(url, data?, config?)
  • put<T>(url, data?, config?)
  • patch<T>(url, data?, config?)
  • delete<T>(url, config?)

Behavior:

  • GET requests: Check cache first, then deduplicate
  • Other methods: Deduplicate only (no response caching)

Current Usage

Files using deduplicatedApiClient:

  • None found (utility exists but may not be actively used)

Files using requestDeduplication directly:

  • None found

Status: ⚠️ Utility is implemented but may not be actively used

Verification

Correct Behavior

  1. Key Generation: Consistent keys for identical requests
  2. Promise Sharing: Multiple identical requests share promise
  3. Error Handling: Errors remove from cache immediately
  4. Cleanup: Automatic and periodic cleanup works
  5. Mutations: POST/PUT/DELETE not deduplicated by default (safe)

⚠️ Potential Issues

  1. FormData Handling: FormData requests use [FormData] flag, may incorrectly deduplicate different uploads
  2. Cache Size: No maximum size limit (could grow unbounded in edge cases)
  3. Usage: Utility may not be actively used (needs verification)

🔧 Recommendations

  1. FormData Improvement: Consider including file name/size in key for FormData requests
  2. Cache Limit: Add maximum cache size with LRU eviction
  3. Usage Audit: Verify if deduplicatedApiClient is actually used in codebase
  4. Metrics: Add metrics to track deduplication effectiveness

Testing Recommendations

  1. Unit Tests: Test key generation, promise sharing, cleanup
  2. Integration Tests: Test with actual API calls
  3. Edge Cases: Test FormData requests, rapid successive calls, error scenarios

Documentation Status

Implementation documented
Usage patterns identified
⚠️ Active usage needs verification
⏭️ Next: Action 2.5.1.6 - Test request deduplication works correctly

Validation

Utility implementation reviewed
Functionality verified
Integration points identified
Potential issues documented
Recommendations provided