Spaces:
Sleeping
Sleeping
| /** | |
| * tools/requestQueue.ts — Request queue for mobile | |
| * | |
| * Gestisce: | |
| * - Concorrenza limitata | |
| * - Timeout e retry | |
| * - Priority queue | |
| * - Abort support | |
| */ | |
| export interface QueuedRequest { | |
| id: string; | |
| priority: number; // 0-10, higher = more important | |
| fn: () => Promise<unknown>; | |
| timeout: number; | |
| retries: number; | |
| resolve: (value: unknown) => void; | |
| reject: (error: Error) => void; | |
| abortSignal?: AbortSignal; | |
| } | |
| export class RequestQueue { | |
| private queue: QueuedRequest[] = []; | |
| private running = 0; | |
| private maxConcurrent = 2; // iPhone-friendly | |
| private requestId = 0; | |
| constructor(maxConcurrent: number = 2) { | |
| this.maxConcurrent = maxConcurrent; | |
| } | |
| /** | |
| * Add request to queue | |
| */ | |
| add<T>( | |
| fn: () => Promise<T>, | |
| options: { | |
| priority?: number; | |
| timeout?: number; | |
| retries?: number; | |
| abortSignal?: AbortSignal; | |
| } = {}, | |
| ): Promise<T> { | |
| return new Promise((resolve, reject) => { | |
| const request: QueuedRequest = { | |
| id: `req_${++this.requestId}`, | |
| priority: options.priority ?? 5, | |
| fn, | |
| timeout: options.timeout ?? 30000, | |
| retries: options.retries ?? 1, | |
| resolve: resolve as (value: unknown) => void, | |
| reject, | |
| abortSignal: options.abortSignal, | |
| }; | |
| this.queue.push(request); | |
| this.queue.sort((a, b) => b.priority - a.priority); | |
| this.process(); | |
| }); | |
| } | |
| /** | |
| * Process queue | |
| */ | |
| private process(): void { | |
| while ( | |
| this.running < this.maxConcurrent && | |
| this.queue.length > 0 | |
| ) { | |
| const request = this.queue.shift(); | |
| if (!request) break; | |
| this.running++; | |
| this.executeRequest(request); | |
| } | |
| } | |
| /** | |
| * Execute single request with retry | |
| */ | |
| private async executeRequest( | |
| request: QueuedRequest, | |
| ): Promise<void> { | |
| let lastError: Error | undefined; | |
| for (let attempt = 0; attempt <= request.retries; attempt++) { | |
| try { | |
| // Check abort signal | |
| if (request.abortSignal?.aborted) { | |
| throw new Error("Richiesta interrotta"); | |
| } | |
| // Execute with timeout | |
| const result = await Promise.race([ | |
| request.fn(), | |
| this.timeout(request.timeout), | |
| ]); | |
| request.resolve(result); | |
| this.running--; | |
| this.process(); | |
| return; | |
| } catch (error) { | |
| lastError = error as Error; | |
| // Don't retry on abort | |
| if ( | |
| lastError.message === "Richiesta interrotta" | |
| ) { | |
| break; | |
| } | |
| // Wait before retry | |
| if (attempt < request.retries) { | |
| await new Promise((resolve) => | |
| setTimeout(resolve, 1000 * (attempt + 1)), | |
| ); | |
| } | |
| } | |
| } | |
| request.reject( | |
| lastError || new Error("Errore sconosciuto"), | |
| ); | |
| this.running--; | |
| this.process(); | |
| } | |
| /** | |
| * Timeout promise | |
| */ | |
| private timeout(ms: number): Promise<never> { | |
| return new Promise((_, reject) => | |
| setTimeout( | |
| () => reject(new Error("Timeout della richiesta")), | |
| ms, | |
| ), | |
| ); | |
| } | |
| /** | |
| * Get queue size | |
| */ | |
| getSize(): number { | |
| return this.queue.length; | |
| } | |
| /** | |
| * Clear queue | |
| */ | |
| clear(): void { | |
| for (const request of this.queue) { | |
| request.reject(new Error("Coda svuotata")); | |
| } | |
| this.queue = []; | |
| } | |
| /** | |
| * Set max concurrent | |
| */ | |
| setMaxConcurrent(max: number): void { | |
| this.maxConcurrent = max; | |
| this.process(); | |
| } | |
| } | |
| // Global queue instance | |
| let globalQueue: RequestQueue | null = null; | |
| export function getGlobalQueue(): RequestQueue { | |
| if (!globalQueue) { | |
| globalQueue = new RequestQueue(2); | |
| } | |
| return globalQueue; | |
| } | |
| export function setGlobalQueueConcurrency( | |
| max: number, | |
| ): void { | |
| getGlobalQueue().setMaxConcurrent(max); | |
| } | |