From 99ad3a87ebdab691c8f71dc1d308b3898a228e5f Mon Sep 17 00:00:00 2001 From: Kollan House Date: Sun, 27 Oct 2024 12:57:59 -0700 Subject: [PATCH] fix: crashing with better handling, update swaps for verbosity --- packages/database/lib/index.ts | 87 +++++++++++++++++++------- packages/indexer/src/builders/swaps.ts | 3 + 2 files changed, 68 insertions(+), 22 deletions(-) diff --git a/packages/database/lib/index.ts b/packages/database/lib/index.ts index ab8e08c..441e011 100644 --- a/packages/database/lib/index.ts +++ b/packages/database/lib/index.ts @@ -5,38 +5,81 @@ import "dotenv/config"; let connectionString = process.env.FUTARCHY_PG_URL; -const pool = new Pool({ +// Add retry configuration +const RETRY_ATTEMPTS = 5; +const INITIAL_RETRY_DELAY = 100; // Start with shorter delay +const MAX_RETRY_DELAY = 2000; // Max backoff delay +const ACQUIRE_TIMEOUT = 10000; // 10 second timeout for acquiring connection + +// Add connection pool configuration +const poolConfig = { connectionString: connectionString, - // https://stackoverflow.com/a/73997522 - // I noticed that there was always a connection timeout error after 9 loops of the startWatchers interval; - // it repeats every 5 seconds and immediately after service start. - // That's a consistent error after 40 seconds. So I'm seeing if idle timeout of 20 seconds works. I suspect it won't though - // since the connection is never idle for more than 5 seconds and yet we still get a connection error. - min: 0, - idleTimeoutMillis: 20 * 1000, - max: 1000, + min: 20, + max: 1000, // Reduced from 1000 to a more reasonable number + idleTimeoutMillis: 30 * 1000, + connectionTimeoutMillis: 5000, + // Add error handling for the pool + async errorHandler(err: Error) { + console.error('Pool error:', err); + } +}; + +const pool = new Pool(poolConfig); + +// Add pool error listeners +pool.on('error', (err) => { + console.error('Unexpected pool error:', err); }); export async function getClient() { return pool.connect(); } +// Modified usingDb function with retry logic export async function usingDb( fn: (connection: NodePgDatabase) => Promise ): Promise { - let client: PoolClient; - try { - client = await pool.connect(); - } catch (e) { - console.error(e); - return; - } - try { - const connection = drizzle(pool, { schema: schemaDefs }); - const result = await fn(connection); - return result; - } finally { - client.release(); + let client: PoolClient | undefined; + let attempts = 0; + + while (attempts < RETRY_ATTEMPTS) { + try { + // Add timeout to connection acquisition + const acquirePromise = pool.connect(); + client = await Promise.race([ + acquirePromise, + new Promise((_, reject) => + setTimeout(() => reject(new Error('Connection acquisition timeout')), ACQUIRE_TIMEOUT) + ) + ]); + + const connection = drizzle(pool, { schema: schemaDefs }); + const result = await fn(connection); + return result; + } catch (e) { + attempts++; + if (attempts === RETRY_ATTEMPTS) { + console.error('Final database connection attempt failed:', e); + throw e; + } + + // Exponential backoff with jitter + const delay = Math.min( + INITIAL_RETRY_DELAY * Math.pow(2, attempts - 1) + Math.random() * 100, + MAX_RETRY_DELAY + ); + + console.warn( + `Database connection attempt ${attempts} failed, retrying in ${delay}ms:`, + e instanceof Error ? e.message : e + ); + + await new Promise(resolve => setTimeout(resolve, delay)); + } finally { + if (client) { + client.release(); + } + } } } diff --git a/packages/indexer/src/builders/swaps.ts b/packages/indexer/src/builders/swaps.ts index b0c1bd3..8981a0b 100644 --- a/packages/indexer/src/builders/swaps.ts +++ b/packages/indexer/src/builders/swaps.ts @@ -83,6 +83,9 @@ export class SwapPersistable { this.ordersRecord )}` ); + if(insertUsersResult.length <= 0) { + logger.warn(`User already exists in db: ${this.ordersRecord.actorAcct}`); + } } // const priceInsertRes =