From 90877b81e054e294090f2d607e829eb010234cd4 Mon Sep 17 00:00:00 2001 From: wpdev Date: Mon, 28 Sep 2026 18:18:56 +0800 Subject: [PATCH] fix(2meet-data-optimizer): entity health sees a running backfill - Backfill batches are scheduled with (entity, group) args; the health panel looked for (entity) alone, never saw one and kept offering to start a backfill, which resets the group's checkpoint - is_backfill_active() checks every group of the entity - Unit bootstrap: wp_next_scheduled() stub honours hook + args - Verify: EntityHealthBackfillTest (2 new); unit 711, phpcs 0, stan OK - PR: PR-137 (manual F-11) --- includes/engine/class-tmdo-entity-health.php | 15 ++++++- tests/bootstrap.php | 2 +- tests/unit/EntityHealthBackfillTest.php | 44 ++++++++++++++++++++ 3 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 tests/unit/EntityHealthBackfillTest.php diff --git a/includes/engine/class-tmdo-entity-health.php b/includes/engine/class-tmdo-entity-health.php index e470ef7..4a5278a 100644 --- a/includes/engine/class-tmdo-entity-health.php +++ b/includes/engine/class-tmdo-entity-health.php @@ -325,7 +325,20 @@ final class TMDO_Entity_Health { return TMDO_Mode_Manager::ALL_MODES[ $idx - 1 ]; } + /** + * Whether a backfill batch is scheduled for any group of the entity. Batches + * are scheduled with (entity, group) args, so looking for (entity) alone + * never found one (2.4.2 PR-137). + * + * @param string $entity_type Entity type. + * @return bool + */ private static function is_backfill_active( string $entity_type ): bool { - return (bool) wp_next_scheduled( 'wpdo_entity_backfill_batch', array( $entity_type ) ); + foreach ( TMDO_Entity_Registry::get_groups_for_type( $entity_type ) as $group ) { + if ( wp_next_scheduled( 'wpdo_entity_backfill_batch', array( $entity_type, $group ) ) ) { + return true; + } + } + return false; } } diff --git a/tests/bootstrap.php b/tests/bootstrap.php index c1fbd05..9e64583 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -180,7 +180,7 @@ if ( ! function_exists( 'do_action_ref_array' ) ) { } } if ( ! function_exists( 'wp_next_scheduled' ) ) { - function wp_next_scheduled( string $hook ): int|false { return false; } + function wp_next_scheduled( string $hook, array $args = array() ): int|false { return $GLOBALS['_wp_next_scheduled'][ $hook ][ md5( serialize( $args ) ) ] ?? false; } } if ( ! function_exists( 'wp_schedule_event' ) ) { function wp_schedule_event( int $t, string $r, string $h ): bool { return true; } diff --git a/tests/unit/EntityHealthBackfillTest.php b/tests/unit/EntityHealthBackfillTest.php new file mode 100644 index 0000000..bf071d2 --- /dev/null +++ b/tests/unit/EntityHealthBackfillTest.php @@ -0,0 +1,44 @@ + 'eh_a', 'type' => 'text' ) ) ); + TMDO_Entity_Registry::register_group( 'user', 'eh_two', array( array( 'key' => 'eh_b', 'type' => 'text' ) ) ); + } + + protected function tearDown(): void { + $GLOBALS['_wp_next_scheduled'] = array(); + TMDO_Entity_Registry::init(); + } + + private function backfill_active( string $entity_type ): bool { + $m = new ReflectionMethod( TMDO_Entity_Health::class, 'is_backfill_active' ); + $m->setAccessible( true ); + return (bool) $m->invoke( null, $entity_type ); + } + + public function test_a_backfill_scheduled_for_one_group_is_seen(): void { + $GLOBALS['_wp_next_scheduled']['wpdo_entity_backfill_batch'][ md5( serialize( array( 'user', 'eh_two' ) ) ) ] = time() + 5; + + $this->assertTrue( $this->backfill_active( 'user' ) ); + $this->assertFalse( $this->backfill_active( 'post' ), 'other entities are not affected' ); + } + + public function test_no_scheduled_batch_means_no_backfill(): void { + $this->assertFalse( $this->backfill_active( 'user' ) ); + } +}