Skip to content

Commit beeeaf9

Browse files
authored
fix: control active cleanup child jobs (#446)
* fix: control active cleanup child jobs * fix: satisfy cleanup control lint * fix: align cleanup control output assignment
1 parent a3c3c5f commit beeeaf9

2 files changed

Lines changed: 58 additions & 12 deletions

File tree

inc/Cli/Commands/WorkspaceCommand.php

Lines changed: 49 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -666,22 +666,59 @@ private function control_cleanup_run_job( string $operation, int $job_id, array
666666
return;
667667
}
668668

669-
$input = array( 'job_id' => $job_id );
670-
if ( 'resume' === $operation ) {
671-
$input['force'] = ! empty( $assoc_args['force'] );
672-
} else {
673-
$input['reason'] = 'cleanup_cancelled';
669+
$target_job_ids = $this->cleanup_run_control_job_ids( $operation, $job_id );
670+
$results = array();
671+
foreach ( $target_job_ids as $target_job_id ) {
672+
$input = array( 'job_id' => $target_job_id );
673+
if ( 'resume' === $operation ) {
674+
$input['force'] = ! empty( $assoc_args['force'] );
675+
} else {
676+
$input['reason'] = 'cleanup_cancelled';
677+
}
678+
679+
$result = $ability->execute( $input );
680+
if ( ! ( $result['success'] ?? false ) ) {
681+
WP_CLI::error( (string) ( $result['error'] ?? 'Cleanup run control failed.' ) );
682+
return;
683+
}
684+
$results[] = $result;
674685
}
675686

676-
$result = $ability->execute( $input );
677-
if ( ! ( $result['success'] ?? false ) ) {
678-
WP_CLI::error( (string) ( $result['error'] ?? 'Cleanup run control failed.' ) );
679-
return;
687+
$output = $results[0] ?? array(
688+
'success' => true,
689+
'job_id' => $job_id,
690+
);
691+
$output['run_id'] = $this->cleanup_run_id( $job_id );
692+
$output['state'] = 'resume' === $operation ? 'running' : 'cancelled';
693+
$output['controlled_job_ids'] = $target_job_ids;
694+
$output['results'] = $results;
695+
$this->render_cleanup_control_result( $output, $assoc_args );
696+
}
697+
698+
/**
699+
* Resolve which Data Machine jobs should be controlled for a job-backed cleanup run.
700+
*
701+
* @param string $operation Cleanup control operation.
702+
* @param int $job_id Cleanup parent job ID.
703+
* @return array<int,int>
704+
*/
705+
private function cleanup_run_control_job_ids( string $operation, int $job_id ): array {
706+
$output = $this->cleanup_run_evidence_store()->read( $this->cleanup_run_id( $job_id ), true, true );
707+
if ( $output instanceof \WP_Error ) {
708+
return array( $job_id );
680709
}
681710

682-
$result['run_id'] = $this->cleanup_run_id( $job_id );
683-
$result['state'] = 'resume' === $operation ? 'running' : 'cancelled';
684-
$this->render_cleanup_control_result( $result, $assoc_args );
711+
$children = (array) ( $output['evidence']['children'] ?? array() );
712+
$processing_ids = array_map( 'intval', (array) ( $children['processing_job_ids'] ?? array() ) );
713+
$failed_ids = array_map( 'intval', (array) ( $children['failed_job_ids'] ?? array() ) );
714+
$pending_ids = array_map( 'intval', (array) ( $children['pending_job_ids'] ?? array() ) );
715+
716+
if ( 'resume' === $operation ) {
717+
$child_targets = array_values( array_unique( array_filter( array_merge( $processing_ids, $failed_ids ) ) ) );
718+
return array() !== $child_targets ? $child_targets : array( $job_id );
719+
}
720+
721+
return array_values( array_unique( array_filter( array_merge( array( $job_id ), $pending_ids, $processing_ids ) ) ) );
685722
}
686723

687724
private function render_cleanup_control_result( array $result, array $assoc_args ): void {

tests/smoke-worktree-cleanup-cli.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -553,9 +553,11 @@ public function execute( array $input ): array {
553553

554554
class FakeRetryJobAbility {
555555
public array $last_input = array();
556+
public array $inputs = array();
556557

557558
public function execute( array $input ): array {
558559
$this->last_input = $input;
560+
$this->inputs[] = $input;
559561
return array(
560562
'success' => true,
561563
'job_id' => (int) $input['job_id'],
@@ -567,9 +569,11 @@ public function execute( array $input ): array {
567569

568570
class FakeFailJobAbility {
569571
public array $last_input = array();
572+
public array $inputs = array();
570573

571574
public function execute( array $input ): array {
572575
$this->last_input = $input;
576+
$this->inputs[] = $input;
573577
return array(
574578
'success' => true,
575579
'job_id' => (int) $input['job_id'],
@@ -714,11 +718,16 @@ public function execute( array $input ): array {
714718
WP_CLI::$logs = array();
715719
WP_CLI::$successes = array();
716720
$command->cleanup( array( 'resume', 'cleanup-run-123' ), array( 'force' => true, 'format' => 'json' ) );
721+
$resume_json = json_decode( WP_CLI::$logs[0] ?? '', true );
722+
datamachine_code_cleanup_assert( array( 125, 127 ) === ( $resume_json['controlled_job_ids'] ?? array() ), 'cleanup resume controls active child jobs before the parent' );
717723
datamachine_code_cleanup_assert( true === ( $retry_job_ability->last_input['force'] ?? null ), 'cleanup resume forwards force retry flag' );
724+
datamachine_code_cleanup_assert( array( 125, 127 ) === array_map( fn( $input ) => (int) ( $input['job_id'] ?? 0 ), $retry_job_ability->inputs ), 'cleanup resume retries processing and failed child jobs' );
718725

719726
WP_CLI::$logs = array();
720727
WP_CLI::$successes = array();
721728
$command->cleanup( array( 'cancel', 'cleanup-run-123' ), array( 'format' => 'json' ) );
729+
$cancel_json = json_decode( WP_CLI::$logs[0] ?? '', true );
730+
datamachine_code_cleanup_assert( array( 123, 125 ) === ( $cancel_json['controlled_job_ids'] ?? array() ), 'cleanup cancel controls parent and active child jobs' );
722731
datamachine_code_cleanup_assert( 'cleanup_cancelled' === ( $fail_job_ability->last_input['reason'] ?? '' ), 'cleanup cancel fails job with cleanup cancellation reason' );
723732

724733
echo "\n[0] list stale output exposes disk fields\n";

0 commit comments

Comments
 (0)