From e8f2a0e7521370211c968e832a6b0d2ceb57e5a3 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Tue, 24 Feb 2026 03:45:47 +0000 Subject: [PATCH] optimize: replace sequential sync loop with Promise.all for concurrency Replaced the sequential for...of loop in flushAudioBlobs with Promise.all and .map() to allow concurrent audio uploads and database updates. This significantly reduces the total synchronization time from N*800ms to approximately 800ms total for small batches. Maintained per-item error handling to ensure robustness. Co-authored-by: alfieprojectsdev <11991855+alfieprojectsdev@users.noreply.github.com> --- field-logic/src/lib/sync.ts | 105 +++++++++++++++++++----------------- 1 file changed, 56 insertions(+), 49 deletions(-) diff --git a/field-logic/src/lib/sync.ts b/field-logic/src/lib/sync.ts index f510eba..10c46d0 100644 --- a/field-logic/src/lib/sync.ts +++ b/field-logic/src/lib/sync.ts @@ -1,51 +1,58 @@ -import { db, saveResponse } from './db'; - -const uploadAudioToDrive = async (blob: Blob, filename: string, token: string): Promise => { - // STUB: Simulate GDrive API upload - console.log(`[Stub] Uploading ${filename} to Google Drive with token ${token}...`); - - // Simulate network delay - await new Promise(resolve => setTimeout(resolve, 800)); - - // Return a fake URL - return `https://drive.google.com/file/d/stub_id_${Date.now()}`; +import { db, saveResponse } from "./db"; + +const uploadAudioToDrive = async ( + blob: Blob, + filename: string, + token: string, +): Promise => { + // STUB: Simulate GDrive API upload + console.log( + `[Stub] Uploading ${filename} to Google Drive with token ${token}...`, + ); + + // Simulate network delay + await new Promise((resolve) => setTimeout(resolve, 800)); + + // Return a fake URL + return `https://drive.google.com/file/d/stub_id_${Date.now()}`; }; -export const flushAudioBlobs = async (token: string = 'test_token') => { - // 1. Find all unsynced blobs - // Dexie boolean index mapping can be tricky, using filter for safety on small datasets - const unsyncedBlobs = await db.blobs.filter(blob => !blob.synced).toArray(); - - console.log(`Found ${unsyncedBlobs.length} items to sync.`); - const results = []; - - for (const record of unsyncedBlobs) { - const { sessionId, nodeId, blob } = record; - const filename = `${sessionId}_${nodeId}.webm`; - - try { - // A. Upload - const url = await uploadAudioToDrive(blob, filename, token); - - // B. Update Responses Table with the link - const metadata = { - type: 'audio', - url: url, - synced_at: new Date().toISOString() - }; - await saveResponse(sessionId, nodeId, metadata); - - // C. Delete local blob (free space) - // Using compound key [sessionId, nodeId] - await db.blobs.where({ sessionId, nodeId }).delete(); - - console.log(`Synced & Flushed: ${filename}`); - results.push({ sessionId, nodeId, status: 'synced', url }); - - } catch (e) { - console.error(`Failed to sync ${filename}`, e); - results.push({ sessionId, nodeId, status: 'failed', error: e }); - } - } - return results; -} +export const flushAudioBlobs = async (token: string = "test_token") => { + // 1. Find all unsynced blobs + // Dexie boolean index mapping can be tricky, using filter for safety on small datasets + const unsyncedBlobs = await db.blobs.filter((blob) => !blob.synced).toArray(); + + console.log(`Found ${unsyncedBlobs.length} items to sync.`); + + const results = await Promise.all( + unsyncedBlobs.map(async (record) => { + const { sessionId, nodeId, blob } = record; + const filename = `${sessionId}_${nodeId}.webm`; + + try { + // A. Upload + const url = await uploadAudioToDrive(blob, filename, token); + + // B. Update Responses Table with the link + const metadata = { + type: "audio", + url: url, + synced_at: new Date().toISOString(), + }; + await saveResponse(sessionId, nodeId, metadata); + + // C. Delete local blob (free space) + // Using compound key [sessionId, nodeId] + await db.blobs.where({ sessionId, nodeId }).delete(); + + console.log(`Synced & Flushed: ${filename}`); + return { sessionId, nodeId, status: "synced", url }; + } catch (e) { + console.error(`Failed to sync ${filename}`, e); + return { sessionId, nodeId, status: "failed", error: e }; + } + }), + ); + + return results; +};