@@ -54,12 +54,17 @@ def start_replication(self, db_name=None, config_file=None):
5454 config_file = self .config_file
5555
5656 try :
57- # Create dynamic config file with isolated paths for this test
58- dynamic_config_file = create_dynamic_config (config_file )
59- print (f"DEBUG: Created dynamic config file: { dynamic_config_file } " )
60-
61- # Use the dynamic config file for process spawning
62- actual_config_file = dynamic_config_file
57+ # Check if config file is already a dynamic config (temporary file)
58+ if '/tmp/' in config_file :
59+ print (f"DEBUG: Using existing dynamic config file: { config_file } " )
60+ actual_config_file = config_file
61+ else :
62+ # Create dynamic config file with isolated paths for this test
63+ dynamic_config_file = create_dynamic_config (config_file )
64+ print (f"DEBUG: Created dynamic config file: { dynamic_config_file } " )
65+
66+ # Use the dynamic config file for process spawning
67+ actual_config_file = dynamic_config_file
6368 except Exception as e :
6469 print (f"WARNING: Failed to create dynamic config, using static config: { e } " )
6570 # Fallback to static config file
@@ -71,14 +76,19 @@ def start_replication(self, db_name=None, config_file=None):
7176 print (f"DEBUG: Ensuring MySQL database '{ db_name } ' exists before starting replication..." )
7277 self .ensure_database_exists (db_name )
7378
74- # CRITICAL: Pre-create database-specific subdirectory for logging
75- # This prevents FileNotFoundError when db_replicator tries to create log files
76- db_dir = os .path .join (self .cfg .binlog_replicator .data_dir , db_name )
79+ # CRITICAL: Pre-create ALL necessary directories for binlog replication
80+ # This prevents FileNotFoundError when processes try to create state/log files
7781 try :
82+ # Ensure parent data directory exists (for state.json)
83+ os .makedirs (self .cfg .binlog_replicator .data_dir , exist_ok = True )
84+ print (f"DEBUG: Pre-created binlog data directory: { self .cfg .binlog_replicator .data_dir } " )
85+
86+ # Ensure database-specific subdirectory exists (for database files)
87+ db_dir = os .path .join (self .cfg .binlog_replicator .data_dir , db_name )
7888 os .makedirs (db_dir , exist_ok = True )
7989 print (f"DEBUG: Pre-created database directory: { db_dir } " )
8090 except Exception as e :
81- print (f"WARNING: Could not pre-create database directory { db_dir } : { e } " )
91+ print (f"WARNING: Could not pre-create binlog directories : { e } " )
8292 # Try to create parent directories first
8393 try :
8494 os .makedirs (self .cfg .binlog_replicator .data_dir , exist_ok = True )
@@ -112,7 +122,16 @@ def start_replication(self, db_name=None, config_file=None):
112122 startup_wait = 5.0 # Increased from 2.0s - give more time for process initialization
113123 retry_attempts = 3
114124 print (f"DEBUG: Waiting { startup_wait } s for replication processes to initialize..." )
115- time .sleep (startup_wait )
125+
126+ # Check for immediate failures after 0.5s to catch startup errors early
127+ time .sleep (0.5 )
128+ if not self ._check_replication_process_health ():
129+ print ("WARNING: Process failed immediately during startup - capturing early error details" )
130+ error_details = self ._get_process_error_details ()
131+ print (f"DEBUG: Early failure details: { error_details } " )
132+
133+ # Continue with full startup wait
134+ time .sleep (startup_wait - 0.5 )
116135
117136 # Verify processes started successfully with retry logic
118137 for attempt in range (retry_attempts ):
@@ -441,13 +460,31 @@ def _get_process_error_details(self):
441460 else :
442461 exit_code = self .binlog_runner .process .poll ()
443462 error_details .append (f"Binlog runner: exit code { exit_code } " )
463+ # Capture subprocess logs if available
464+ if hasattr (self .binlog_runner , 'log_file' ) and self .binlog_runner .log_file :
465+ try :
466+ self .binlog_runner .log_file .seek (0 )
467+ log_content = self .binlog_runner .log_file .read ()
468+ if log_content .strip ():
469+ error_details .append (f"Binlog logs: { log_content [- 200 :]} " ) # Last 200 chars
470+ except Exception as e :
471+ error_details .append (f"Binlog log read error: { e } " )
444472
445473 if self .db_runner :
446474 if self .db_runner .process is None :
447475 error_details .append ("DB runner: process is None" )
448476 else :
449477 exit_code = self .db_runner .process .poll ()
450478 error_details .append (f"DB runner: exit code { exit_code } " )
479+ # Capture subprocess logs if available
480+ if hasattr (self .db_runner , 'log_file' ) and self .db_runner .log_file :
481+ try :
482+ self .db_runner .log_file .seek (0 )
483+ log_content = self .db_runner .log_file .read ()
484+ if log_content .strip ():
485+ error_details .append (f"DB logs: { log_content [- 200 :]} " ) # Last 200 chars
486+ except Exception as e :
487+ error_details .append (f"DB log read error: { e } " )
451488
452489 # Add environment info
453490 from tests .conftest import TEST_DB_NAME
0 commit comments