feat: batch sync content using action scheduler#247
Open
Kallyan01 wants to merge 30 commits into
Open
Conversation
Codecov Report❌ Patch coverage is Additional details and impacted files@@ 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
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
…tion Scheduler and added db cleanup code
… asynchronous processing
…ement , improved sync UI
…g on history table
… 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
…ent on SiteIndexableEntities component
76563ae to
cdb6f2d
Compare
Contributor
There was a problem hiding this comment.
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 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; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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
Additional Info
Checklist