Skip to content

feat: batch sync content using action scheduler#247

Open
Kallyan01 wants to merge 30 commits into
mainfrom
feat/as-batch-sync-content
Open

feat: batch sync content using action scheduler#247
Kallyan01 wants to merge 30 commits into
mainfrom
feat/as-batch-sync-content

Conversation

@Kallyan01

@Kallyan01 Kallyan01 commented Jun 18, 2026

Copy link
Copy Markdown
Collaborator

What

Implements a full asynchronous batch sync/reindex system using Action Scheduler. Reindexing no longer runs synchronously in a single request; it now fans out into parent/child jobs that process in the background with progress tracking, retry logic, cancellation, and job history.

Why

The existing synchronous reindex blocked PHP execution and timed out on large sites with many posts or many child sites, which could not reliably complete a reindex. Moving to Action Scheduler lets each sync batch run independently, survive failures via exponential-backoff retries, and report real-time progress back to the admin UI.

Related Issue(s):

How

AI Disclosure

Took the help of the Claude Sonnet 4.6 model to verify future scalability issues and testcases.

Testing Instructions

Validate the reindexing process using a large dataset and ensure that the entire reindex operation completes successfully without failures.

Screenshots

image image image

Additional Info

Checklist

  • I have read the Contribution Guidelines.
  • I have read the Development Guidelines.
  • I have added necessary tests to cover my changes.
  • I have updated the project documentation as needed.
  • My code has detailed inline documentation.
  • My code is tested to the best of my abilities.
  • My code passes all lints, tests, and checks.
Open WordPress Playground Preview

@Kallyan01 Kallyan01 changed the title Feat/as batch sync content feat: batch sync content using action scheduler Jun 18, 2026
@Kallyan01 Kallyan01 marked this pull request as ready for review June 19, 2026 10:22
@codecov-commenter

codecov-commenter commented Jun 19, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 44.69657% with 1048 lines in your changes missing coverage. Please review.
✅ Project coverage is 65.79%. Comparing base (ecd9f13) to head (cdb6f2d).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
inc/Modules/Scheduler/Job_Scheduler.php 21.07% 337 Missing ⚠️
inc/Modules/Schema/Job_Repository.php 0.00% 231 Missing ⚠️
inc/Modules/Scheduler/Job_REST_Controller.php 71.55% 200 Missing ⚠️
inc/Modules/Jobs/Abstract_Job.php 60.91% 68 Missing ⚠️
inc/Modules/Jobs/Reindex_Job.php 3.27% 59 Missing ⚠️
inc/Modules/Jobs/Sync_Job.php 4.34% 44 Missing ⚠️
inc/Modules/Jobs/Registry.php 0.00% 32 Missing ⚠️
uninstall.php 0.00% 24 Missing ⚠️
inc/Modules/Schema/Job_Schema.php 0.00% 17 Missing ⚠️
inc/Modules/Rest/Search_Controller.php 89.04% 16 Missing ⚠️
... and 3 more
Additional details and impacted files

Impacted file tree graph

@@              Coverage Diff              @@
##               main     #247       +/-   ##
=============================================
- Coverage     86.46%   65.79%   -20.68%     
- Complexity      543      969      +426     
=============================================
  Files            22       31        +9     
  Lines          1988     3859     +1871     
=============================================
+ Hits           1719     2539      +820     
- Misses          269     1320     +1051     
Flag Coverage Δ
unit 65.79% <44.69%> (-20.68%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
inc/Main.php 100.00% <100.00%> (ø)
inc/Modules/Search/Index.php 88.69% <83.33%> (-1.40%) ⬇️
inc/Modules/Search/Watcher.php 66.66% <47.05%> (-33.34%) ⬇️
inc/Modules/Scheduler/Bootstrap.php 0.00% <0.00%> (ø)
inc/Modules/Rest/Search_Controller.php 82.75% <89.04%> (+4.03%) ⬆️
inc/Modules/Schema/Job_Schema.php 0.00% <0.00%> (ø)
uninstall.php 0.00% <0.00%> (ø)
inc/Modules/Jobs/Registry.php 0.00% <0.00%> (ø)
inc/Modules/Jobs/Sync_Job.php 4.34% <4.34%> (ø)
inc/Modules/Jobs/Reindex_Job.php 3.27% <3.27%> (ø)
... and 4 more
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@Kallyan01 Kallyan01 requested a review from justlevine June 19, 2026 14:09
Kallyan01 and others added 26 commits July 3, 2026 19:59
… in CI

Strauss 0.27.0 validates the GitHub OAuth token format, but the
GITHUB_TOKEN provided by GitHub Actions uses the ghs_* format
(contains underscores) which fails Strauss's regex validation.

Fix: run `composer install --no-scripts` to skip post-install-cmd,
then run `composer run prefix-namespaces` in a separate step with
`COMPOSER_AUTH: '{}'` to prevent Strauss from reading the invalid token.

Applies to both reusable-phpcs.yml and reusable-phpstan.yml.

Co-authored-by: Kallyan01 <48629100+Kallyan01@users.noreply.github.com>
…nd PHP compatibility

- Add mock for /re-index/status fetch that fires on component mount
- Update re-index modal test to use Close button and check dialog removal
- Mock fetchHistory calls for modal open and reindex handler flows
- Fix add_option deprecated empty string autoload parameter (use false)
- Guard direct SQL query with prepare result type check
- Update PHPStan types and ActionScheduler stub
- Use COMPOSER_HOME isolation for strauss to avoid CI token validation failure
- Upgrade strauss from 0.27.0 to 0.27.3
- Use overlayClassName on Modal with CSS :has() instead of wrapper div blur
- Fix CSS formatting inconsistencies
@Kallyan01 Kallyan01 force-pushed the feat/as-batch-sync-content branch from 76563ae to cdb6f2d Compare July 3, 2026 16:38
Copilot AI review requested due to automatic review settings July 3, 2026 16:38

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR migrates OneSearch reindexing from a synchronous, single-request flow to an asynchronous batch/job system built on Action Scheduler, with REST endpoints + admin UI for progress, history, cancellation, and retries.

Changes:

  • Introduces a job framework (Abstract_Job + Registry) and persistence layer (custom jobs table + repository) to track active and terminal jobs.
  • Updates reindex + watcher flows to enqueue async Sync_Job batches and orchestrate full reindexes via Reindex_Job, with UI polling and history views.
  • Adds/updates PHPUnit + Jest coverage and PHPStan stubs to support the new scheduler-driven behavior.

Reviewed changes

Copilot reviewed 48 out of 50 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
uninstall.php Cleans up new job-related options/transients and drops the custom jobs table on uninstall.
tests/phpunit/Integration/Modules/Settings/SettingsTest.php Ensures options are cleared between tests to prevent cross-test leakage.
tests/phpunit/Integration/Modules/Search/WatcherTest.php Updates watcher expectations from synchronous Algolia calls to async scheduling.
tests/phpunit/Integration/Modules/Search/SettingsTest.php Adds setup/teardown cleanup for site-type option to stabilize integration tests.
tests/phpunit/Integration/Modules/Search/IndexTest.php Resets static/transient settings-init flags to avoid test contamination.
tests/phpunit/Integration/Modules/Search/AlgoliaTest.php Cleans options/transients pre-test for deterministic Algolia integration tests.
tests/phpunit/Integration/Modules/Scheduler/Job_REST_Controller_Test.php Adds REST endpoint integration tests for job listing/status/retry/cancel/history.
tests/phpunit/Integration/Modules/Rest/Search_Controller_GoverningSiteTest.php Adds reindex status/409 conflict coverage for governing-site REST flows.
tests/phpunit/Integration/Modules/Rest/Search_Controller_ConsumerSiteTest.php Adds reindex status/409 conflict coverage for consumer-site REST flows.
tests/phpunit/Integration/Modules/Rest/Governing_Data_HandlerTest.php Adds teardown cleanup to prevent option/transient leakage.
tests/phpunit/Integration/Modules/Rest/Governing_Data_Controller_GoverningSiteTest.php Adds teardown cleanup for governing REST controller tests.
tests/phpstan/stubs/action-scheduler.php Adds Action Scheduler stubs for PHPStan analysis.
tests/php/Unit/Modules/Scheduler/Job_Scheduler_Test.php Adds unit tests for scheduler persistence, active/terminal job behavior, and cancellation.
tests/php/Unit/Modules/Jobs/Sync_Job_Test.php Adds unit tests for Sync_Job defaults and validation behavior.
tests/php/Unit/Modules/Jobs/Reindex_Job_Test.php Adds unit tests for Reindex_Job defaults and data handling.
tests/php/Unit/Modules/Jobs/Registry_Test.php Adds unit tests for job Registry singleton registration/resolve behavior.
tests/js/SiteIndexableEntities.test.tsx Updates admin UI tests for new reindex status/history flows and modal behavior.
phpstan.neon.dist Adds Action Scheduler stubs to PHPStan scan list.
onesearch.php Loads Action Scheduler early from vendor when not already available.
inc/Modules/Search/Watcher.php Replaces inline Algolia sync on post transition with scheduling a Sync_Job (+ fallback).
inc/Modules/Search/Index.php Moves settings init flag to static + transient to reduce repeated Algolia settings pushes across AS runs.
inc/Modules/Schema/Job_Schema.php Adds schema management for the custom jobs table.
inc/Modules/Schema/Job_Repository.php Adds DB access layer for job persistence/counters/history retrieval.
inc/Modules/Scheduler/Bootstrap.php Initializes scheduler module, registers built-in job types, fires extensibility hook.
inc/Modules/Rest/Search_Controller.php Reworks reindex endpoint to create parent Reindex_Job + child Sync_Job batches, adds status endpoint and locking/state persistence.
inc/Modules/Jobs/Sync_Job.php Implements leaf job to sync/delete posts in Algolia in batches.
inc/Modules/Jobs/Reindex_Job.php Implements parent job to clear index and schedule child Sync_Job batches from WP_Query paging.
inc/Modules/Jobs/Registry.php Adds registry mapping job type names to concrete job classes.
inc/Modules/Jobs/Abstract_Job.php Adds core job lifecycle/progress/retry/serialization support.
inc/Main.php Runs Job_Schema upgrade and registers scheduler + job REST controller modules.
composer.lock Adds woocommerce/action-scheduler dependency lock entry.
assets/src/types/global.d.ts Adds shared UI type for status rendering.
assets/src/css/admin.scss Adds styles for reindex modal, spinners, progress UI, history table, and details views.
assets/src/components/SiteIndexableEntities/utils.ts Adds formatting + normalization helpers and history site derivation logic.
assets/src/components/SiteIndexableEntities/useReindexJob.ts Adds polling, cancel/retry, restore-from-status, and history/details logic for reindex UI.
assets/src/components/SiteIndexableEntities/types.ts Adds TS types for entities, jobs, history, and per-site job state.
assets/src/components/SiteIndexableEntities/SiteRow.tsx Renders per-site row with expandable batch list + keyboard accessibility.
assets/src/components/SiteIndexableEntities/ReindexModalContent.tsx Renders reindex modal content (start, loading, progress panel, history table).
assets/src/components/SiteIndexableEntities/ReindexModal.tsx Wraps modal routing between progress view and history details view.
assets/src/components/SiteIndexableEntities/JobStatusBadge.tsx Adds reusable status badge/text renderer.
assets/src/components/SiteIndexableEntities/index.tsx Rebuilds indexable entities UI to integrate async reindex + modal/history flows.
assets/src/components/SiteIndexableEntities/HistoryTable.tsx Adds job history table UI with click/keyboard handling for details.
assets/src/components/SiteIndexableEntities/HistoryPagination.tsx Adds pagination UI for job history.
assets/src/components/SiteIndexableEntities/HistoryDetailsView.tsx Adds per-site/batch history detail view + retry-failed-batches UX.
assets/src/components/SiteIndexableEntities/EntitySiteCard.tsx Extracts entity selector card per site.
assets/src/components/SiteIndexableEntities/constants.ts Defines status labels and terminal-status list.
assets/src/components/SiteIndexableEntities/BatchRow.tsx Renders individual batch status rows (including error preview).
assets/src/components/SiteIndexableEntities.tsx Removes legacy monolithic SiteIndexableEntities component in favor of modularized folder implementation.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +277 to +290
$lock_key = self::REINDEX_STATE_TRANSIENT . '_lock';
if ( ! add_option( $lock_key, '1', '', false ) ) {
return new \WP_Error(
'onesearch_reindex_active',
__( 'A re-index is already in progress. Cancel it or wait for it to complete before starting a new one.', 'onesearch' ),
[ 'status' => 409 ]
);
}

// Auto-expire the lock after 5 minutes in case the process crashes
// before cleanup. wp_schedule_single_action is preferred but not
// guaranteed to be available during plugin init, so we use a transient
// as a safety net.
set_transient( $lock_key . '_expiry', '1', 5 * MINUTE_IN_SECONDS );
Comment on lines +79 to +85
// Clear existing records before reindexing.
$indexer = new Index();
$indexer->delete_by(
[
'filters' => sprintf( 'site_url:"%s"', Utils::normalize_url( get_site_url() ) ),
]
);
Comment on lines +80 to +84
$indexer->delete_by(
[
'filters' => sprintf( 'site_post_id:"%s"', $site_post_id ),
]
);
Comment on lines +67 to +72
/**
* @param array<string, mixed> $args
* @return ActionScheduler_Action[]
*/
function as_get_scheduled_actions( array $args = [] ): array {}
} No newline at end of file
Comment on lines +46 to +50
export interface JobStatus {
id: string;
status: string;
progress: number;
progress_total: number;
Comment on lines +76 to +80
<td>
<Text variant="muted">
{ job.group || 'reindex' }
</Text>
</td>
Comment thread assets/src/css/admin.scss
Comment on lines +586 to +591
@keyframes onesearch-spin {

to {
transform: rotate(360deg);
}
}
Comment on lines +2 to +10
/**
* Tests for Job_REST_Controller.
*
* @package OneSearch\Tests\Unit\Modules\Scheduler
*/

declare( strict_types = 1 );

namespace OneSearch\Tests\Unit\Modules\Rest;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants