@@ -3,10 +3,23 @@ import { BigQueryExport } from './bigquery.js'
33
44export class FirestoreBatch {
55 constructor ( ) {
6- this . firestore = new Firestore ( )
6+ this . firestore = new Firestore ( {
7+ // Increase timeout to 10 minutes for large batch operations
8+ gaxOptions : {
9+ grpc : {
10+ max_receive_message_length : 100 * 1024 * 1024 , // 100MB
11+ max_send_message_length : 100 * 1024 * 1024 , // 100MB
12+ 'grpc.max_connection_idle_ms' : 5 * 60 * 1000 , // 5 minutes
13+ 'grpc.keepalive_time_ms' : 30 * 1000 , // 30 seconds
14+ 'grpc.keepalive_timeout_ms' : 60 * 1000 , // 1 minute
15+ 'grpc.keepalive_permit_without_calls' : true
16+ }
17+ }
18+ } )
719 this . bigquery = new BigQueryExport ( )
8- this . batchSize = 500
9- this . maxConcurrentBatches = 200
20+ this . batchSizeDelete = 500
21+ this . batchSizeWrite = 400 // Reduced batch size for better performance
22+ this . maxConcurrentBatches = 100 // Reduced concurrent batches to avoid overwhelming
1023 }
1124
1225 queueBatch ( operation ) {
@@ -28,14 +41,34 @@ export class FirestoreBatch {
2841
2942 async commitBatches ( ) {
3043 console . log ( `Committing ${ this . batchPromises . length } batches to ${ this . collectionName } ` )
44+
3145 await Promise . all (
32- this . batchPromises . map ( async ( batchPromise ) => await batchPromise . commit ( )
33- . catch ( ( error ) => {
34- console . error ( 'Error committing batch:' , error )
35- throw error
36- } )
37- )
46+ this . batchPromises . map ( async ( batchPromise , index ) => {
47+ const retryCount = 3
48+ let lastError
49+
50+ for ( let attempt = 1 ; attempt <= retryCount ; attempt ++ ) {
51+ try {
52+ await batchPromise . commit ( )
53+ return
54+ } catch ( error ) {
55+ lastError = error
56+ console . warn ( `Batch ${ index } attempt ${ attempt } failed:` , error . message )
57+
58+ if ( attempt < retryCount ) {
59+ // Exponential backoff: 2^attempt seconds
60+ const delayMs = Math . pow ( 2 , attempt ) * 1000
61+ console . log ( `Retrying batch ${ index } in ${ delayMs } ms...` )
62+ await new Promise ( resolve => setTimeout ( resolve , delayMs ) )
63+ }
64+ }
65+ }
66+
67+ console . error ( `Batch ${ index } failed after ${ retryCount } attempts:` , lastError )
68+ throw lastError
69+ } )
3870 )
71+
3972 this . batchPromises = [ ]
4073 }
4174
@@ -71,7 +104,7 @@ export class FirestoreBatch {
71104 }
72105
73106 while ( true ) {
74- const snapshot = await collectionQuery . limit ( this . batchSize * this . maxConcurrentBatches ) . get ( )
107+ const snapshot = await collectionQuery . limit ( this . batchSizeDelete * this . maxConcurrentBatches ) . get ( )
75108 if ( snapshot . empty ) {
76109 break
77110 }
@@ -127,7 +160,8 @@ export class FirestoreBatch {
127160
128161 async export ( query , exportConfig ) {
129162 this . firestore . settings ( {
130- databaseId : exportConfig . database
163+ databaseId : exportConfig . database ,
164+ timeout : 10 * 60 * 1000 // 10 minutes timeout
131165 } )
132166 this . collectionName = exportConfig . collection
133167 this . collectionType = exportConfig . type
0 commit comments