Files
roa2web-service-auto/shared/database/oracle_pool.py
Marius Mutu 6b13ffa183 Initial commit: ROA2WEB - FastAPI + Vue.js + Telegram Bot
Modern ERP Reports Application with microservices architecture

Tech Stack:
- Backend: FastAPI + python-oracledb (Oracle DB integration)
- Frontend: Vue.js 3 + PrimeVue + Vite
- Telegram Bot: python-telegram-bot + SQLite
- Infrastructure: Shared database pool, JWT authentication, SSH tunnel

Features:
- FastAPI backend with async Oracle connection pool
- Vue.js 3 responsive frontend with PrimeVue components
- Telegram bot alternative interface
- Microservices architecture with shared components
- Complete deployment support (Linux Docker + Windows IIS)
- Comprehensive testing (Playwright E2E + pytest)

Repository Structure:
- reports-app/ - Main application (backend, frontend, telegram-bot)
- shared/ - Shared components (database pool, auth, utils)
- deployment/ - Deployment scripts (Linux & Windows)
- docs/ - Project documentation
- security/ - Security scanning and git hooks
2025-10-25 14:55:08 +03:00

119 lines
4.5 KiB
Python

"""
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()