Skip to content

Commit e8fd830

Browse files
committed
fix: restore missing now timestamp in create_run and auto-release lock on initialization failure
1 parent 63e980d commit e8fd830

3 files changed

Lines changed: 39 additions & 24 deletions

File tree

‎core/engine/migration_engine.php‎

Lines changed: 30 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -119,33 +119,41 @@ public function start_run(string $source_system, migration_config_dto $config):
119119
throw new \RuntimeException("Another migration is already running for source: {$source_system}");
120120
}
121121

122-
$run_state = $this->state_manager->create_run($run_id, $source_system, $source_version, $config);
122+
try
123+
{
124+
$run_state = $this->state_manager->create_run($run_id, $source_system, $source_version, $config);
123125

124-
// Resolve ordered steps
125-
$requested_steps = !empty($config->selected_steps) ? $config->selected_steps : $provider->get_supported_steps();
126-
$ordered_steps = $this->step_registry->resolve_order($requested_steps, $source_system);
126+
// Resolve ordered steps
127+
$requested_steps = !empty($config->selected_steps) ? $config->selected_steps : $provider->get_supported_steps();
128+
$ordered_steps = $this->step_registry->resolve_order($requested_steps, $source_system);
127129

128-
$steps_init = [];
129-
foreach ($ordered_steps as $order => $step_name)
130-
{
131-
$total = $provider->get_total_records($step_name, $config);
132-
$max_id = $provider->get_max_source_id($step_name, $config);
133-
$steps_init[] = [
134-
'step_name' => $step_name,
135-
'step_order' => $order + 1,
136-
'total_records' => $total,
137-
'max_source_id' => $max_id,
138-
];
139-
}
130+
$steps_init = [];
131+
foreach ($ordered_steps as $order => $step_name)
132+
{
133+
$total = $provider->get_total_records($step_name, $config);
134+
$max_id = $provider->get_max_source_id($step_name, $config);
135+
$steps_init[] = [
136+
'step_name' => $step_name,
137+
'step_order' => $order + 1,
138+
'total_records' => $total,
139+
'max_source_id' => $max_id,
140+
];
141+
}
140142

141-
$this->state_manager->init_steps($run_id, $steps_init);
142-
$this->state_manager->update_run_status($run_id, 'ready', $ordered_steps[0] ?? '');
143+
$this->state_manager->init_steps($run_id, $steps_init);
144+
$this->state_manager->update_run_status($run_id, 'ready', $ordered_steps[0] ?? '');
143145

144-
// Release initial creation lock so it is not held idly before batches start
145-
$this->lock_manager->release($lock_name, $run_id);
146+
// Release initial creation lock so it is not held idly before batches start
147+
$this->lock_manager->release($lock_name, $run_id);
146148

147-
$run_state = $this->state_manager->get_run($run_id);
148-
return $run_state;
149+
$run_state = $this->state_manager->get_run($run_id);
150+
return $run_state;
151+
}
152+
catch (\Throwable $e)
153+
{
154+
$this->lock_manager->release($lock_name, $run_id);
155+
throw $e;
156+
}
149157
}
150158

151159
/**

‎core/state/lock_manager.php‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,17 +85,23 @@ public function acquire(string $lock_name, string $run_id, string $worker_type =
8585

8686
// Check if previous run is completed or failed
8787
$prev_run_status = '';
88+
$run_exists = false;
8889
if (!empty($existing_lock['run_id']))
8990
{
9091
$runs_table = str_replace('migration_locks', 'migration_runs', $this->table_name);
9192
$sql = 'SELECT status FROM ' . $runs_table . ' WHERE run_id = ' . "'" . $this->db->sql_escape($existing_lock['run_id']) . "'";
9293
$r_res = $this->db->sql_query($sql);
93-
$prev_run_status = (string)$this->db->sql_fetchfield('status');
94+
$row = $this->db->sql_fetchrow($r_res);
95+
if ($row)
96+
{
97+
$run_exists = true;
98+
$prev_run_status = (string)$row['status'];
99+
}
94100
$this->db->sql_freeresult($r_res);
95101
}
96102

97103
$is_stale = ((int)$existing_lock['heartbeat_at'] < $stale_threshold);
98-
$is_finished = in_array($prev_run_status, ['completed', 'finalized', 'rolled_back', 'abandoned', 'failed'], true);
104+
$is_finished = (!$run_exists && !empty($existing_lock['run_id'])) || in_array($prev_run_status, ['completed', 'finalized', 'rolled_back', 'abandoned', 'failed'], true);
99105

100106
// If the lock is held by the EXACT same full worker_id, refresh heartbeat
101107
if ($existing_lock['worker_id'] === $full_worker_id && $existing_lock['run_id'] === $run_id)

‎core/state/state_manager.php‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ public function generate_run_id(): string
114114
*/
115115
public function create_run(string $run_id, string $source_system, string $source_version, migration_config_dto $config): run_state_dto
116116
{
117+
$now = time();
117118
$options = $config->to_array(true); // Must include database credentials so batch workers can connect
118119

119120
$data = [

0 commit comments

Comments
 (0)