mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-24 10:51:13 -05:00
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:
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user