# 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**:
```typescript
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`**:
```typescript
// Multiple identical requests share the same promise
const promise1 = deduplicatedApiClient.get('/tracks');
const promise2 = deduplicatedApiClient.get('/tracks');
// promise1 === promise2 (same promise instance)
```

**Direct Usage**:
```typescript
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
