Add DNS retry logic to Drift initialization
- Handles transient network failures (EAI_AGAIN, ENOTFOUND, ETIMEDOUT) - Automatically retries up to 3 times with 2s delay between attempts - Logs retry attempts for monitoring - Prevents 500 errors from temporary DNS hiccups - Fixes: n8n workflow failures during brief network issues Impact: - Improves reliability during DNS/network instability - Reduces false negatives (missed trades due to transient errors) - User-friendly retry logs for diagnostics
This commit is contained in:
@@ -75,8 +75,52 @@ export class DriftService {
|
||||
console.log('✅ Drift service created for wallet:', this.wallet.publicKey.toString())
|
||||
}
|
||||
|
||||
/**
|
||||
* Retry helper for handling transient network failures (DNS, timeouts)
|
||||
*/
|
||||
private async retryOperation<T>(
|
||||
operation: () => Promise<T>,
|
||||
maxRetries: number = 3,
|
||||
delayMs: number = 2000,
|
||||
operationName: string = 'operation'
|
||||
): Promise<T> {
|
||||
let lastError: Error | null = null
|
||||
|
||||
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
||||
try {
|
||||
return await operation()
|
||||
} catch (error: any) {
|
||||
lastError = error
|
||||
|
||||
// Check if it's a transient network error
|
||||
const isTransient =
|
||||
error?.message?.includes('fetch failed') ||
|
||||
error?.message?.includes('EAI_AGAIN') ||
|
||||
error?.message?.includes('ENOTFOUND') ||
|
||||
error?.message?.includes('ETIMEDOUT') ||
|
||||
error?.message?.includes('ECONNREFUSED') ||
|
||||
error?.code === 'EAI_AGAIN' ||
|
||||
error?.cause?.code === 'EAI_AGAIN'
|
||||
|
||||
if (!isTransient || attempt === maxRetries) {
|
||||
// Non-transient error or max retries reached - fail immediately
|
||||
throw error
|
||||
}
|
||||
|
||||
console.log(`⚠️ ${operationName} failed (attempt ${attempt}/${maxRetries}): ${error?.message || error}`)
|
||||
console.log(`⏳ Retrying in ${delayMs}ms...`)
|
||||
|
||||
// Wait before retry
|
||||
await new Promise(resolve => setTimeout(resolve, delayMs))
|
||||
}
|
||||
}
|
||||
|
||||
throw lastError || new Error(`${operationName} failed after ${maxRetries} retries`)
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize Drift client and subscribe to account updates
|
||||
* Includes automatic retry for transient network failures (DNS, timeouts)
|
||||
*/
|
||||
async initialize(): Promise<void> {
|
||||
if (this.isInitialized) {
|
||||
@@ -87,33 +131,36 @@ export class DriftService {
|
||||
try {
|
||||
console.log('🚀 Initializing Drift Protocol client...')
|
||||
|
||||
// Initialize Drift SDK (gets program IDs and config)
|
||||
const sdkConfig = initialize({
|
||||
env: this.config.env === 'devnet' ? 'devnet' : 'mainnet-beta'
|
||||
})
|
||||
// Wrap initialization in retry logic to handle DNS failures
|
||||
await this.retryOperation(async () => {
|
||||
// Initialize Drift SDK (gets program IDs and config)
|
||||
const sdkConfig = initialize({
|
||||
env: this.config.env === 'devnet' ? 'devnet' : 'mainnet-beta'
|
||||
})
|
||||
|
||||
// Create Drift client with manual wallet and SDK config
|
||||
this.driftClient = new DriftClient({
|
||||
connection: this.connection,
|
||||
wallet: this.wallet as any, // Type assertion for compatibility
|
||||
programID: new PublicKey(sdkConfig.DRIFT_PROGRAM_ID),
|
||||
opts: {
|
||||
commitment: 'confirmed',
|
||||
},
|
||||
})
|
||||
// Create Drift client with manual wallet and SDK config
|
||||
this.driftClient = new DriftClient({
|
||||
connection: this.connection,
|
||||
wallet: this.wallet as any, // Type assertion for compatibility
|
||||
programID: new PublicKey(sdkConfig.DRIFT_PROGRAM_ID),
|
||||
opts: {
|
||||
commitment: 'confirmed',
|
||||
},
|
||||
})
|
||||
|
||||
// Subscribe to Drift account updates
|
||||
await this.driftClient.subscribe()
|
||||
console.log('✅ Drift client subscribed to account updates')
|
||||
// Subscribe to Drift account updates (this makes RPC calls)
|
||||
await this.driftClient.subscribe()
|
||||
console.log('✅ Drift client subscribed to account updates')
|
||||
|
||||
// Get user account
|
||||
this.user = this.driftClient.getUser()
|
||||
// Get user account
|
||||
this.user = this.driftClient.getUser()
|
||||
}, 3, 2000, 'Drift initialization')
|
||||
|
||||
this.isInitialized = true
|
||||
console.log('✅ Drift service initialized successfully')
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Failed to initialize Drift service:', error)
|
||||
console.error('❌ Failed to initialize Drift service after retries:', error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user