- 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
166 lines
5.2 KiB
Markdown
166 lines
5.2 KiB
Markdown
# 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
|