@@ -11,7 +11,7 @@ import { MarketOrder } from '../fastTransfer/types';
11
11
import { Block } from './EVMWatcher' ;
12
12
import { BigNumber } from 'ethers' ;
13
13
import axios from 'axios' ;
14
-
14
+ import { sleep } from '@wormhole-foundation/wormhole-monitor-common' ;
15
15
export type BlockTag = 'finalized' | 'safe' | 'latest' ;
16
16
17
17
export class FTEVMWatcher extends Watcher {
@@ -39,7 +39,6 @@ export class FTEVMWatcher extends Watcher {
39
39
this . rpc = RPCS_BY_CHAIN [ this . network ] [ this . chain ] ! ;
40
40
this . parser = new TokenRouterParser ( this . network , chain , this . provider ) ;
41
41
this . logger . debug ( 'FTWatcher' , network , chain , finalizedBlockTag ) ;
42
-
43
42
// hacky way to not connect to the db in tests
44
43
// this is to allow ci to run without a db
45
44
if ( isTest ) {
@@ -128,28 +127,58 @@ export class FTEVMWatcher extends Watcher {
128
127
const { results, lastBlockTime } = await this . parser . getFTResultsInRange ( fromBlock , toBlock ) ;
129
128
130
129
if ( results . length ) {
131
- try {
132
- await this . saveFastTransfers ( results ) ;
133
- } catch ( e ) {
134
- this . logger . error ( e ) ;
135
- }
130
+ await this . saveFastTransfers ( results , fromBlock , toBlock ) ;
136
131
}
137
132
return makeBlockKey ( toBlock . toString ( ) , lastBlockTime . toString ( ) ) ;
138
133
}
139
134
140
- async saveFastTransfers ( fastTransfers : MarketOrder [ ] ) : Promise < void > {
141
- // this is to allow ci to run without a db
135
+ // saves fast transfers in smaller batches to reduce the impact in any case anything fails
136
+ // retry with exponential backoff is used here
137
+ async saveFastTransfers (
138
+ fastTransfers : MarketOrder [ ] ,
139
+ fromBlock : number ,
140
+ toBlock : number
141
+ ) : Promise < void > {
142
142
if ( ! this . pg ) {
143
143
return ;
144
144
}
145
- this . logger . debug ( `saving ${ fastTransfers . length } fast transfers` ) ;
146
145
147
- // Batch insert the fast transfers
148
- try {
149
- await this . pg ( 'market_orders' ) . insert ( fastTransfers ) . onConflict ( 'fast_vaa_id' ) . merge ( ) ;
150
- } catch ( e ) {
151
- this . logger . error ( `Error saving fast transfers ${ e } ` ) ;
146
+ const batchSize = 50 ;
147
+ const maxRetries = 3 ;
148
+ const totalBatches = Math . ceil ( fastTransfers . length / batchSize ) ;
149
+
150
+ this . logger . debug (
151
+ `Attempting to save ${ fastTransfers . length } fast transfers in batches of ${ batchSize } `
152
+ ) ;
153
+
154
+ for ( let batchIndex = 0 ; batchIndex < fastTransfers . length ; batchIndex += batchSize ) {
155
+ const batch = fastTransfers . slice ( batchIndex , batchIndex + batchSize ) ;
156
+ const batchNumber = Math . floor ( batchIndex / batchSize ) + 1 ;
157
+
158
+ for ( let attempt = 1 ; attempt <= maxRetries ; attempt ++ ) {
159
+ try {
160
+ await this . pg ( 'market_orders' ) . insert ( batch ) . onConflict ( 'fast_vaa_id' ) . merge ( ) ;
161
+ this . logger . info (
162
+ `Successfully saved batch ${ batchNumber } /${ totalBatches } (${ batch . length } transfers)`
163
+ ) ;
164
+ break ;
165
+ } catch ( e ) {
166
+ if ( attempt === maxRetries ) {
167
+ this . logger . error (
168
+ `Failed to save batch ${ batchNumber } /${ totalBatches } from block ${ fromBlock } - ${ toBlock } after ${ maxRetries } attempts` ,
169
+ e
170
+ ) ;
171
+ } else {
172
+ // Wait before retrying (exponential backoff)
173
+ this . logger . warn (
174
+ `Attempt ${ attempt } failed for batch ${ batchNumber } /${ totalBatches } . Retrying...`
175
+ ) ;
176
+ await sleep ( 1000 * Math . pow ( 2 , attempt - 1 ) ) ;
177
+ }
178
+ }
179
+ }
152
180
}
181
+ this . logger . info ( `Completed saving fast transfers from block ${ fromBlock } - ${ toBlock } ` ) ;
153
182
}
154
183
}
155
184
0 commit comments