Troubleshooting Guide¶
This guide covers common issues, solutions, and best practices when working with dbsync-py.
Common Connection Issues¶
Database Connection Failures¶
Problem: "Connection refused" or "Could not connect to server"¶
Symptoms:
sqlalchemy.exc.OperationalError: (psycopg2.OperationalError) could not connect to server: Connection refused
Solutions:
-
Check Database Service:
-
Verify Connection Parameters:
-
Check Network Configuration:
Problem: "Authentication failed"¶
Symptoms:
sqlalchemy.exc.OperationalError: (psycopg2.OperationalError) FATAL: password authentication failed for user
Solutions:
-
Verify Credentials:
-
Check PostgreSQL Authentication:
Problem: "Database does not exist"¶
Symptoms:
sqlalchemy.exc.OperationalError: (psycopg2.OperationalError) FATAL: database "cexplorer" does not exist
Solutions:
-
Verify Database Name:
-
Check DB Sync Setup:
SSL/TLS Connection Issues¶
Problem: SSL connection errors¶
Solutions:
-
Disable SSL for Local Connections:
-
Configure SSL Properly:
Performance Issues¶
Slow Query Performance¶
Problem: Queries taking too long¶
Diagnosis:
-
Enable Query Logging:
-
Profile Query Execution:
Solutions:
-
Use Proper Indexing:
-
Implement Pagination:
-
Use Eager Loading:
from sqlalchemy.orm import joinedload, selectinload # Load related objects to avoid N+1 queries transactions = session.query(Transaction).options( joinedload(Transaction.block), selectinload(Transaction.outputs) ).limit(100).all() # Now accessing tx.block won't trigger additional queries for tx in transactions: print(f"Transaction in block {tx.block.block_no}")
Memory Issues¶
Problem: High memory usage or out-of-memory errors¶
Solutions:
-
Use Session Batching:
def process_large_dataset(session, batch_size=1000): offset = 0 while True: batch = session.query(Transaction).offset(offset).limit(batch_size).all() if not batch: break # Process batch for tx in batch: process_transaction(tx) # Clear session to free memory session.expunge_all() offset += batch_size -
Use Streaming Queries:
-
Close Sessions Properly:
# Always close sessions session = create_session() try: # Your operations pass finally: session.close() # Or use context manager from contextlib import contextmanager @contextmanager def get_session(): session = create_session() try: yield session finally: session.close() with get_session() as session: # Your operations pass
Data Consistency Issues¶
Stale Data Problems¶
Problem: Getting outdated information¶
Solutions:
-
Check Database Sync Status:
from dbsync.models import Block from sqlalchemy import func from datetime import datetime, timedelta def check_db_sync_status(session): # Get latest block latest_block = session.query(Block).order_by(Block.block_no.desc()).first() if latest_block: time_diff = datetime.utcnow() - latest_block.time print(f"Latest block: {latest_block.block_no}") print(f"Block time: {latest_block.time}") print(f"Time behind: {time_diff}") if time_diff > timedelta(minutes=10): print("WARNING: Database appears to be behind!") return latest_block -
Refresh Session Data:
Foreign Key Constraint Errors¶
Problem: Referential integrity issues¶
Solutions:
- Check Data Integrity:
def check_referential_integrity(session): """Check for common referential integrity issues.""" # Check for orphaned transactions orphaned_txs = session.query(Transaction).filter( ~Transaction.block_id.in_(session.query(Block.id_)) ).count() if orphaned_txs > 0: print(f"Found {orphaned_txs} orphaned transactions!") # Check for orphaned transaction outputs orphaned_outputs = session.query(TransactionOutput).filter( ~TransactionOutput.tx_id.in_(session.query(Transaction.id_)) ).count() if orphaned_outputs > 0: print(f"Found {orphaned_outputs} orphaned outputs!")
Model and Type Issues¶
Type Conversion Errors¶
Problem: Bytes/hex conversion issues¶
Symptoms:
Solutions:
-
Proper Hash Handling:
# Converting hex string to bytes for database queries tx_hash_str = "a1b2c3d4e5f6..." tx_hash_bytes = bytes.fromhex(tx_hash_str) tx = session.query(Transaction).filter( Transaction.hash == tx_hash_bytes ).first() # Converting bytes back to hex for display if tx: print(f"Transaction hash: {tx.hash.hex()}") -
Handle None Values:
-
Validate Input Data:
def validate_tx_hash(hash_str): """Validate transaction hash format.""" if not hash_str: raise ValueError("Hash cannot be empty") if len(hash_str) != 64: raise ValueError("Transaction hash must be 64 characters") try: bytes.fromhex(hash_str) except ValueError: raise ValueError("Invalid hexadecimal characters in hash") return hash_str.lower()
Model Relationship Issues¶
Problem: Lazy loading errors¶
Symptoms:
Solutions:
-
Use Eager Loading:
# Load related objects upfront from sqlalchemy.orm import joinedload transaction = session.query(Transaction).options( joinedload(Transaction.block), joinedload(Transaction.outputs) ).filter(Transaction.id_ == tx_id).first() # Now you can access relationships even after session closes session.close() print(f"Transaction in block {transaction.block.block_no}") -
Keep Session Open:
-
Detach and Merge Objects:
Async/Await Issues¶
Async Session Problems¶
Problem: "RuntimeError: There is no current event loop"¶
Solutions:
-
Proper Event Loop Management:
-
Avoid Mixing Sync and Async:
Problem: "coroutine was never awaited"¶
Solutions:
- Await All Async Operations:
Best Practices Summary¶
Connection Management¶
-
Use Connection Pooling:
-
Always Close Sessions:
Query Optimization¶
-
Use Appropriate Loading Strategies:
-
Implement Proper Pagination:
-
Use Indexes Wisely:
Error Handling¶
-
Implement Retry Logic:
-
Validate Input Data:
Monitoring and Debugging¶
-
Enable Logging:
-
Monitor Performance:
This troubleshooting guide should help resolve most common issues encountered when working with dbsync-py. For issues not covered here, check the project's GitHub issues or create a new issue with detailed information about your problem.