CRITICAL FIX: Robust DB + drops attribute + no duplicate logging (complete rewrite)
Some checks failed
CI / Frontend Lint & Type Check (push) Has been cancelled
CI / Frontend Build (push) Has been cancelled
CI / Backend Lint (push) Has been cancelled
CI / Backend Tests (push) Has been cancelled
CI / Docker Build (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
Deploy / Build & Push Images (push) Has been cancelled
Deploy / Deploy to Server (push) Has been cancelled
Deploy / Notify (push) Has been cancelled
Some checks failed
CI / Frontend Lint & Type Check (push) Has been cancelled
CI / Frontend Build (push) Has been cancelled
CI / Backend Lint (push) Has been cancelled
CI / Backend Tests (push) Has been cancelled
CI / Docker Build (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
Deploy / Build & Push Images (push) Has been cancelled
Deploy / Deploy to Server (push) Has been cancelled
Deploy / Notify (push) Has been cancelled
This commit is contained in:
@ -65,20 +65,18 @@ SWITCH_CONFIG = {
|
|||||||
# Setup logging (avoid duplicate handlers)
|
# Setup logging (avoid duplicate handlers)
|
||||||
logger = logging.getLogger("pounce_zone_sync")
|
logger = logging.getLogger("pounce_zone_sync")
|
||||||
logger.setLevel(logging.INFO)
|
logger.setLevel(logging.INFO)
|
||||||
if not logger.handlers: # Only add handlers once
|
if not logger.handlers:
|
||||||
formatter = logging.Formatter('%(asctime)s [%(levelname)s] %(message)s')
|
formatter = logging.Formatter('%(asctime)s [%(levelname)s] %(message)s')
|
||||||
# Console handler
|
|
||||||
console = logging.StreamHandler()
|
console = logging.StreamHandler()
|
||||||
console.setFormatter(formatter)
|
console.setFormatter(formatter)
|
||||||
logger.addHandler(console)
|
logger.addHandler(console)
|
||||||
# File handler
|
|
||||||
try:
|
try:
|
||||||
LOG_FILE.parent.mkdir(parents=True, exist_ok=True)
|
LOG_FILE.parent.mkdir(parents=True, exist_ok=True)
|
||||||
file_handler = logging.FileHandler(LOG_FILE)
|
file_handler = logging.FileHandler(LOG_FILE)
|
||||||
file_handler.setFormatter(formatter)
|
file_handler.setFormatter(formatter)
|
||||||
logger.addHandler(file_handler)
|
logger.addHandler(file_handler)
|
||||||
except Exception:
|
except Exception:
|
||||||
pass # File logging optional
|
pass
|
||||||
|
|
||||||
|
|
||||||
class ZoneSyncResult:
|
class ZoneSyncResult:
|
||||||
@ -88,15 +86,39 @@ class ZoneSyncResult:
|
|||||||
self.success = False
|
self.success = False
|
||||||
self.domain_count = 0
|
self.domain_count = 0
|
||||||
self.drops_count = 0
|
self.drops_count = 0
|
||||||
|
self.drops: list = [] # CRITICAL: List of (domain, tld) tuples for DB storage
|
||||||
self.error: Optional[str] = None
|
self.error: Optional[str] = None
|
||||||
self.duration_seconds = 0
|
self.duration_seconds = 0
|
||||||
|
|
||||||
|
|
||||||
async def get_db_session():
|
async def get_db_session():
|
||||||
"""Create async database session"""
|
"""Create async database session - ROBUST VERSION (reads .env directly)"""
|
||||||
from app.config import settings
|
# Read DATABASE_URL directly from .env to avoid import issues when running standalone
|
||||||
|
env_file = Path("/home/user/pounce/backend/.env")
|
||||||
|
if not env_file.exists():
|
||||||
|
env_file = Path(__file__).parent.parent / ".env"
|
||||||
|
|
||||||
engine = create_async_engine(settings.database_url.replace("sqlite://", "sqlite+aiosqlite://"))
|
db_url = None
|
||||||
|
if env_file.exists():
|
||||||
|
for line in env_file.read_text().splitlines():
|
||||||
|
if line.startswith("DATABASE_URL="):
|
||||||
|
db_url = line.split("=", 1)[1].strip().strip('"').strip("'")
|
||||||
|
break
|
||||||
|
|
||||||
|
# Default to SQLite if not found
|
||||||
|
if not db_url:
|
||||||
|
db_url = "sqlite:///./domainwatch.db"
|
||||||
|
logger.warning(f"DATABASE_URL not found in .env, using default: {db_url}")
|
||||||
|
|
||||||
|
# Convert to async driver
|
||||||
|
if "sqlite://" in db_url and "aiosqlite" not in db_url:
|
||||||
|
db_url = db_url.replace("sqlite://", "sqlite+aiosqlite://")
|
||||||
|
elif "postgresql://" in db_url and "asyncpg" not in db_url:
|
||||||
|
db_url = db_url.replace("postgresql://", "postgresql+asyncpg://")
|
||||||
|
|
||||||
|
logger.info(f"DB connection: {db_url[:50]}...")
|
||||||
|
|
||||||
|
engine = create_async_engine(db_url, echo=False)
|
||||||
async_session = sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)
|
async_session = sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)
|
||||||
return async_session()
|
return async_session()
|
||||||
|
|
||||||
@ -556,7 +578,7 @@ async def main():
|
|||||||
results.append(result)
|
results.append(result)
|
||||||
|
|
||||||
# Store drops IMMEDIATELY after each TLD (crash-safe)
|
# Store drops IMMEDIATELY after each TLD (crash-safe)
|
||||||
if hasattr(result, 'drops') and result.drops:
|
if result.drops:
|
||||||
await store_tld_drops(result.drops, tld)
|
await store_tld_drops(result.drops, tld)
|
||||||
|
|
||||||
# Rate limit: wait between downloads
|
# Rate limit: wait between downloads
|
||||||
@ -571,7 +593,7 @@ async def main():
|
|||||||
results.append(result)
|
results.append(result)
|
||||||
|
|
||||||
# Store drops IMMEDIATELY
|
# Store drops IMMEDIATELY
|
||||||
if hasattr(result, 'drops') and result.drops:
|
if result.drops:
|
||||||
await store_tld_drops(result.drops, tld)
|
await store_tld_drops(result.drops, tld)
|
||||||
|
|
||||||
# Cleanup stray files
|
# Cleanup stray files
|
||||||
@ -621,4 +643,4 @@ async def main():
|
|||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
exit_code = asyncio.run(main())
|
exit_code = asyncio.run(main())
|
||||||
sys.exit(exit_code)
|
sys.exit(exit_code)
|
||||||
|
|||||||
Reference in New Issue
Block a user