You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
152 lines
5.7 KiB
152 lines
5.7 KiB
"""
|
|
Test safe seeding with lock detection and retry logic
|
|
"""
|
|
|
|
import time
|
|
from django.core.management.base import BaseCommand
|
|
from django.db import connection
|
|
from django.db.utils import OperationalError, IntegrityError
|
|
from apps.hadis.models import HadisSect, HadisStatus, HadisTag
|
|
|
|
|
|
class Command(BaseCommand):
|
|
help = 'Test safe seeding with lock detection'
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(*args, **kwargs)
|
|
self.retry_delay = 1 # seconds
|
|
self.max_retries = 3
|
|
|
|
def handle(self, **options):
|
|
self.stdout.write("🧪 Testing safe seeding with lock detection...")
|
|
|
|
# Check database status
|
|
self.check_database_locks()
|
|
|
|
# Test creating a few records
|
|
self.test_sect_creation()
|
|
self.test_status_creation()
|
|
self.test_tag_creation()
|
|
|
|
self.stdout.write(self.style.SUCCESS("✅ All tests completed successfully!"))
|
|
|
|
def safe_execute_with_retry(self, operation_name, operation_func, *args, **kwargs):
|
|
"""Execute database operation with retry logic for handling locks"""
|
|
for attempt in range(self.max_retries):
|
|
try:
|
|
self.stdout.write(f" Attempting {operation_name} (attempt {attempt + 1}/{self.max_retries})")
|
|
result = operation_func(*args, **kwargs)
|
|
self.stdout.write(f" ✓ {operation_name} completed successfully")
|
|
return result
|
|
|
|
except OperationalError as e:
|
|
error_msg = str(e).lower()
|
|
if 'database is locked' in error_msg or 'deadlock' in error_msg:
|
|
self.stdout.write(
|
|
self.style.WARNING(
|
|
f" ⚠ Database lock detected in {operation_name}: {str(e)}"
|
|
)
|
|
)
|
|
if attempt < self.max_retries - 1:
|
|
self.stdout.write(f" ⏳ Waiting {self.retry_delay} seconds before retry...")
|
|
time.sleep(self.retry_delay)
|
|
self.retry_delay = min(self.retry_delay * 1.5, 5)
|
|
else:
|
|
self.stdout.write(
|
|
self.style.ERROR(f" ❌ Max retries reached for {operation_name}")
|
|
)
|
|
raise
|
|
else:
|
|
self.stdout.write(
|
|
self.style.ERROR(f" ❌ Non-lock error in {operation_name}: {str(e)}")
|
|
)
|
|
raise
|
|
|
|
except IntegrityError as e:
|
|
if 'unique' in str(e).lower() or 'duplicate' in str(e).lower():
|
|
self.stdout.write(
|
|
self.style.WARNING(f" ⚠ Record already exists in {operation_name}: {str(e)}")
|
|
)
|
|
return None
|
|
else:
|
|
self.stdout.write(
|
|
self.style.ERROR(f" ❌ Integrity error in {operation_name}: {str(e)}")
|
|
)
|
|
raise
|
|
|
|
except Exception as e:
|
|
self.stdout.write(
|
|
self.style.ERROR(f" ❌ Unexpected error in {operation_name}: {str(e)}")
|
|
)
|
|
raise
|
|
|
|
def check_database_locks(self):
|
|
"""Check for existing database locks"""
|
|
try:
|
|
with connection.cursor() as cursor:
|
|
cursor.execute("SELECT 1;")
|
|
cursor.fetchone()
|
|
self.stdout.write("✓ Database connection is working")
|
|
|
|
except Exception as e:
|
|
self.stdout.write(
|
|
self.style.WARNING(f"Could not check database: {str(e)}")
|
|
)
|
|
|
|
def create_test_sect(self):
|
|
"""Create a test sect"""
|
|
sect, created = HadisSect.objects.get_or_create(
|
|
sect_type='test',
|
|
defaults={
|
|
'title': 'Test Sect',
|
|
'is_active': True,
|
|
'order': 999
|
|
}
|
|
)
|
|
if created:
|
|
self.stdout.write(" ✅ Created test sect")
|
|
else:
|
|
self.stdout.write(" ✓ Test sect already exists")
|
|
return sect
|
|
|
|
def create_test_status(self):
|
|
"""Create a test status"""
|
|
status, created = HadisStatus.objects.get_or_create(
|
|
title='Test Status',
|
|
defaults={
|
|
'color': 'blue',
|
|
'order': 999
|
|
}
|
|
)
|
|
if created:
|
|
self.stdout.write(" ✅ Created test status")
|
|
else:
|
|
self.stdout.write(" ✓ Test status already exists")
|
|
return status
|
|
|
|
def create_test_tag(self):
|
|
"""Create a test tag"""
|
|
tag, created = HadisTag.objects.get_or_create(
|
|
title='Test Tag',
|
|
defaults={'status': True}
|
|
)
|
|
if created:
|
|
self.stdout.write(" ✅ Created test tag")
|
|
else:
|
|
self.stdout.write(" ✓ Test tag already exists")
|
|
return tag
|
|
|
|
def test_sect_creation(self):
|
|
"""Test sect creation with retry logic"""
|
|
self.stdout.write("🕌 Testing sect creation...")
|
|
self.safe_execute_with_retry("Create test sect", self.create_test_sect)
|
|
|
|
def test_status_creation(self):
|
|
"""Test status creation with retry logic"""
|
|
self.stdout.write("📊 Testing status creation...")
|
|
self.safe_execute_with_retry("Create test status", self.create_test_status)
|
|
|
|
def test_tag_creation(self):
|
|
"""Test tag creation with retry logic"""
|
|
self.stdout.write("🏷️ Testing tag creation...")
|
|
self.safe_execute_with_retry("Create test tag", self.create_test_tag)
|