Soumik Bose commited on
Commit
693fb3b
·
1 Parent(s): fdc6d72

connection_broke_fix

Browse files
Files changed (1) hide show
  1. controller.py +48 -7
controller.py CHANGED
@@ -226,9 +226,13 @@ class ConnectionPoolManager:
226
  self._pg_pools[db_url] = pg_pool.ThreadedConnectionPool(1, 10, **db_config)
227
  return self._pg_pools[db_url].getconn()
228
 
229
- def return_postgres_connection(self, db_url, conn):
 
 
 
 
230
  if db_url in self._pg_pools and conn:
231
- self._pg_pools[db_url].putconn(conn)
232
 
233
  pool_manager = ConnectionPoolManager()
234
 
@@ -318,6 +322,9 @@ def _run_mysql_synchronously(db_url: str, sql_query: str, max_rows: int = 20, li
318
  connection = None
319
  cursor = None
320
  response = {"success": False, "results": None, "columns": None, "rowCount": 0, "executionTime": 0.0, "error": None, "is_aggregate": False, "limited": False, "message": ""}
 
 
 
321
 
322
  try:
323
  connection = pool_manager.get_mysql_connection(db_url)
@@ -361,17 +368,36 @@ def _run_mysql_synchronously(db_url: str, sql_query: str, max_rows: int = 20, li
361
  return response
362
 
363
  except Exception as e:
 
 
 
 
 
364
  response["error"] = str(e)
365
  return response
366
  finally:
367
- if cursor: cursor.close()
368
- if connection: connection.close() # Returns to pool
 
 
 
 
 
 
 
 
 
 
369
 
370
  def _run_postgres_synchronously(db_url: str, sql_query: str, max_rows: int = 20, limited: bool = False) -> dict:
371
  start_time = time.time()
372
  connection = None
373
  cursor = None
374
  response = {"success": False, "results": None, "columns": None, "rowCount": 0, "executionTime": 0.0, "error": None, "is_aggregate": False, "limited": False, "message": ""}
 
 
 
 
375
  try:
376
  connection = pool_manager.get_postgres_connection(db_url)
377
  cursor = connection.cursor(cursor_factory=RealDictCursor)
@@ -413,12 +439,27 @@ def _run_postgres_synchronously(db_url: str, sql_query: str, max_rows: int = 20,
413
  response.update({"success": True, "results": clean_results, "columns": columns, "rowCount": len(results), "executionTime": time.time() - start_time})
414
  return response
415
  except Exception as e:
416
- if connection: connection.rollback()
 
 
 
 
 
 
 
 
 
 
417
  response["error"] = str(e)
418
  return response
419
  finally:
420
- if cursor: cursor.close()
421
- if connection: pool_manager.return_postgres_connection(db_url, connection)
 
 
 
 
 
422
 
423
 
424
  # ==============================================================================
 
226
  self._pg_pools[db_url] = pg_pool.ThreadedConnectionPool(1, 10, **db_config)
227
  return self._pg_pools[db_url].getconn()
228
 
229
+ def return_postgres_connection(self, db_url, conn, close=False):
230
+ """
231
+ Returns connection to pool.
232
+ If close=True, the connection is discarded (used for dead connections).
233
+ """
234
  if db_url in self._pg_pools and conn:
235
+ self._pg_pools[db_url].putconn(conn, close=close)
236
 
237
  pool_manager = ConnectionPoolManager()
238
 
 
322
  connection = None
323
  cursor = None
324
  response = {"success": False, "results": None, "columns": None, "rowCount": 0, "executionTime": 0.0, "error": None, "is_aggregate": False, "limited": False, "message": ""}
325
+
326
+ # Flag for bad connections
327
+ connection_broken = False
328
 
329
  try:
330
  connection = pool_manager.get_mysql_connection(db_url)
 
368
  return response
369
 
370
  except Exception as e:
371
+ # Detect broken pipe or connection lost errors in MySQL
372
+ err_str = str(e).lower()
373
+ if "lost connection" in err_str or "gone away" in err_str or isinstance(e, mysql.connector.errors.OperationalError):
374
+ connection_broken = True
375
+
376
  response["error"] = str(e)
377
  return response
378
  finally:
379
+ try:
380
+ if cursor: cursor.close()
381
+ except: pass
382
+
383
+ if connection:
384
+ if connection_broken:
385
+ # Discard dead connection (do NOT return to pool)
386
+ try: connection.close()
387
+ except: pass
388
+ else:
389
+ # Return healthy connection to pool
390
+ connection.close()
391
 
392
  def _run_postgres_synchronously(db_url: str, sql_query: str, max_rows: int = 20, limited: bool = False) -> dict:
393
  start_time = time.time()
394
  connection = None
395
  cursor = None
396
  response = {"success": False, "results": None, "columns": None, "rowCount": 0, "executionTime": 0.0, "error": None, "is_aggregate": False, "limited": False, "message": ""}
397
+
398
+ # Flag to determine if connection is dead
399
+ connection_broken = False
400
+
401
  try:
402
  connection = pool_manager.get_postgres_connection(db_url)
403
  cursor = connection.cursor(cursor_factory=RealDictCursor)
 
439
  response.update({"success": True, "results": clean_results, "columns": columns, "rowCount": len(results), "executionTime": time.time() - start_time})
440
  return response
441
  except Exception as e:
442
+ # Detect fatal connection errors
443
+ err_msg = str(e).lower()
444
+ if "closed" in err_msg or "terminat" in err_msg or isinstance(e, (psycopg2.InterfaceError, psycopg2.OperationalError)):
445
+ connection_broken = True
446
+
447
+ if connection and not connection_broken:
448
+ try:
449
+ connection.rollback()
450
+ except Exception:
451
+ connection_broken = True
452
+
453
  response["error"] = str(e)
454
  return response
455
  finally:
456
+ try:
457
+ if cursor: cursor.close()
458
+ except: pass
459
+
460
+ if connection:
461
+ # If broken, set close=True to discard it from pool
462
+ pool_manager.return_postgres_connection(db_url, connection, close=connection_broken)
463
 
464
 
465
  # ==============================================================================