""" Oracle Database Connection Pool - Shared între toate aplicațiile ROA2WEB Folosește oracledb cu connection pooling pentru performance optimă """ import oracledb import os from contextlib import asynccontextmanager from typing import Optional import logging logger = logging.getLogger(__name__) class OraclePool: """ Singleton class pentru Oracle connection pool Partajat între toate microservicele ROA2WEB """ _instance: Optional['OraclePool'] = None _pool: Optional[oracledb.ConnectionPool] = None def __new__(cls): if cls._instance is None: cls._instance = super(OraclePool, cls).__new__(cls) return cls._instance async def initialize(self, **config): """Inițializează pool-ul de conexiuni""" if self._pool is None: # Check if we have DSN or individual parameters dsn = config.get('dsn', os.getenv('ORACLE_DSN')) if dsn: # Use DSN connection self._pool = oracledb.create_pool( user=config.get('user', os.getenv('ORACLE_USER')), password=config.get('password', os.getenv('ORACLE_PASSWORD')), dsn=dsn, min=config.get('min_connections', 2), max=config.get('max_connections', 10), increment=config.get('increment', 1), getmode=oracledb.POOL_GETMODE_WAIT ) else: # Use individual parameters (host, port, sid) self._pool = oracledb.create_pool( user=config.get('user', os.getenv('ORACLE_USER')), password=config.get('password', os.getenv('ORACLE_PASSWORD')), host=config.get('host', os.getenv('ORACLE_HOST', 'localhost')), port=config.get('port', int(os.getenv('ORACLE_PORT', '1526'))), sid=config.get('sid', os.getenv('ORACLE_SID', 'ROA')), min=config.get('min_connections', 2), max=config.get('max_connections', 10), increment=config.get('increment', 1), getmode=oracledb.POOL_GETMODE_WAIT ) logger.info(f"Oracle pool created with {self._pool.opened} connections") @asynccontextmanager async def get_connection(self): """Context manager pentru obținerea unei conexiuni din pool""" if self._pool is None: raise RuntimeError("Pool not initialized. Call initialize() first.") connection = None try: connection = self._pool.acquire() logger.debug("Connection acquired from pool") yield connection finally: if connection is not None: connection.close() logger.debug("Connection returned to pool") async def execute_query(self, query: str, parameters=None): """ Execute a SQL query and return all results Based on official Oracle python-oracledb patterns """ if self._pool is None: raise RuntimeError("Pool not initialized. Call initialize() first.") connection = None try: connection = self._pool.acquire() logger.debug(f"Executing query: {query[:100]}...") with connection.cursor() as cursor: if parameters: cursor.execute(query, parameters) else: cursor.execute(query) # Check if this is a SELECT statement if query.strip().upper().startswith('SELECT') or query.strip().upper().startswith('WITH'): return cursor.fetchall() else: # For DML statements, return affected row count connection.commit() return cursor.rowcount except Exception as e: if connection: connection.rollback() logger.error(f"Query execution failed: {str(e)}") raise finally: if connection is not None: connection.close() logger.debug("Connection returned to pool") async def close_pool(self): """Închide pool-ul de conexiuni""" if self._pool is not None: self._pool.close() self._pool = None logger.info("Oracle pool closed") # Instance globală pentru folosire în toate aplicațiile oracle_pool = OraclePool()