Implement Phase 4: Transaction Resilience

This commit implements Phase 4 of the Sacred Pipeline, focusing on transaction resilience. It introduces:

- **Timeout Detection & Recovery**: New utilities in `src/lib/timeoutDetection.ts` to detect, categorize (minor, moderate, critical), and provide recovery strategies for timeouts across various sources (fetch, Supabase, edge functions, database). Includes a `withTimeout` wrapper.
- **Lock Auto-Release**: Implemented in `src/lib/moderation/lockAutoRelease.ts` to automatically release submission locks on error, timeout, abandonment, or inactivity. Includes mechanisms for unload events and inactivity monitoring.
- **Idempotency Key Lifecycle Management**: A new module `src/lib/idempotencyLifecycle.ts` to track idempotency keys through their states (pending, processing, completed, failed, expired) using IndexedDB. Includes automatic cleanup of expired keys.
- **Enhanced Idempotency Helpers**: Updated `src/lib/idempotencyHelpers.ts` to integrate with the new lifecycle management, providing functions to generate, register, validate, and update the status of idempotency keys.
- **Transaction Resilience Hook**: A new hook `src/hooks/useTransactionResilience.ts` that combines timeout handling, lock auto-release, and idempotency key management for robust transaction execution.
- **Submission Queue Integration**: Updated `src/hooks/useSubmissionQueue.ts` to leverage the new submission queue and idempotency lifecycle functionalities.
- **Documentation**: Added `PHASE4_TRANSACTION_RESILIENCE.md` detailing the implemented features and their usage.
This commit is contained in:
gpt-engineer-app[bot]
2025-11-07 15:03:12 +00:00
parent 095278dafd
commit 34dbe2e262
7 changed files with 1397 additions and 12 deletions

View File

@@ -3,8 +3,18 @@
*
* Provides helper functions for generating and managing idempotency keys
* for moderation operations to prevent duplicate requests.
*
* Integrated with idempotencyLifecycle.ts for full lifecycle tracking.
*/
import {
registerIdempotencyKey,
updateIdempotencyStatus,
getIdempotencyRecord,
isIdempotencyKeyValid,
type IdempotencyRecord,
} from './idempotencyLifecycle';
/**
* Generate a deterministic idempotency key for a moderation action
*
@@ -88,3 +98,62 @@ export function getRetryAfter(error: unknown): number {
export function sleep(ms: number): Promise<void> {
return new Promise(resolve => setTimeout(resolve, ms));
}
/**
* Generate and register a new idempotency key with lifecycle tracking
*
* @param action - The moderation action type
* @param submissionId - The submission ID
* @param itemIds - Array of item IDs being processed
* @param userId - The moderator's user ID
* @returns Idempotency key and record
*/
export async function generateAndRegisterKey(
action: 'approval' | 'rejection' | 'retry',
submissionId: string,
itemIds: string[],
userId: string
): Promise<{ key: string; record: IdempotencyRecord }> {
const key = generateIdempotencyKey(action, submissionId, itemIds, userId);
const record = await registerIdempotencyKey(key, action, submissionId, itemIds, userId);
return { key, record };
}
/**
* Validate and mark idempotency key as processing
*
* @param key - Idempotency key to validate
* @returns True if valid and marked as processing
*/
export async function validateAndStartProcessing(key: string): Promise<boolean> {
const isValid = await isIdempotencyKeyValid(key);
if (!isValid) {
return false;
}
const record = await getIdempotencyRecord(key);
// Only allow transition from pending to processing
if (record?.status !== 'pending') {
return false;
}
await updateIdempotencyStatus(key, 'processing');
return true;
}
/**
* Mark idempotency key as completed
*/
export async function markKeyCompleted(key: string): Promise<void> {
await updateIdempotencyStatus(key, 'completed');
}
/**
* Mark idempotency key as failed
*/
export async function markKeyFailed(key: string, error: string): Promise<void> {
await updateIdempotencyStatus(key, 'failed', error);
}