fix: auto-reset stale is_publishing flag to prevent infinite Creating spinner#792
fix: auto-reset stale is_publishing flag to prevent infinite Creating spinner#792superdav42 merged 2 commits intomainfrom
Conversation
…g' spinner When publish_pending_site() sets is_publishing=true but the PHP process is killed mid-creation (OOM, timeout, server restart), the flag stays true permanently. The AJAX polling handler returns 'running' forever, and the Action Scheduler retry bails out because it sees is_publishing=true. Fix: - Add publishing_started_at timestamp to Site model, recorded automatically when set_publishing(true) is called - Add is_publishing_stale() method with configurable timeout (default 5 min) - check_pending_site_created() now detects stale state, resets the flag, re-enqueues the async action, and returns 'stopped' so the JS retry flow can pick it up - Pre-2.5.3 serialized objects (without timestamp) are treated as stale when is_publishing is true, since the process that set it is clearly gone Reported by Michael Carter (maatos.app) — site accessible immediately but thank-you page stuck on 'Creating' indefinitely.
📝 WalkthroughWalkthroughThe changes implement stale publishing state detection for pending sites. A new Changes
Sequence DiagramsequenceDiagram
participant MembMgr as Membership Manager
participant PendSite as Pending Site
participant Site as Site Model
participant DB as Database
participant Logger as Logger
participant Queue as Async Queue
MembMgr->>PendSite: check_pending_site_created()
PendSite->>Site: is_publishing_stale()
Site-->>PendSite: true (timeout exceeded)
PendSite->>Site: set_publishing(false)
Site->>DB: record timestamp reset
PendSite->>MembMgr: update_pending_site()
MembMgr->>DB: persist updated state
MembMgr->>Logger: log stale publishing detected
Logger-->>MembMgr: event logged
MembMgr->>Queue: re-enqueue wu_async_publish_pending_site
Queue-->>MembMgr: task queued
MembMgr-->>MembMgr: return publish_status: stopped
Estimated Code Review Effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
🔨 Build Complete - Ready for Testing!📦 Download Build Artifact (Recommended)Download the zip build, upload to WordPress and test:
🌐 Test in WordPress Playground (Very Experimental)Click the link below to instantly test this PR in your browser - no installation needed! Login credentials: |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@inc/managers/class-membership-manager.php`:
- Around line 221-227: The code currently enqueues
wu_enqueue_async_action('wu_async_publish_pending_site', ...) and then returns
wp_send_json(['publish_status' => 'stopped']), creating two competing retry
sources; remove the Action Scheduler enqueue here so only the frontend retry
(publish_status => 'stopped') is relied on, or alternatively gate the enqueue
behind a check that ensures Membership::publish_pending_site() won't be retried
by both sources (e.g., consult the serialized is_publishing flag or a new marker
before calling wu_enqueue_async_action). Update the block containing
wu_enqueue_async_action and wp_send_json to either drop the enqueue call
entirely or add the guard so only a single retry path is used.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: a5ea38a7-c5cc-4f3a-867e-f8dd2603c664
📒 Files selected for processing (3)
inc/managers/class-membership-manager.phpinc/models/class-site.phptests/WP_Ultimo/Models/Site_Test.php
| /* | ||
| * Re-enqueue the async action so Action Scheduler retries | ||
| * the site creation without waiting for the next cron tick. | ||
| */ | ||
| wu_enqueue_async_action('wu_async_publish_pending_site', ['membership_id' => $membership->get_id()], 'membership'); | ||
|
|
||
| wp_send_json(['publish_status' => 'stopped']); |
There was a problem hiding this comment.
Avoid starting two retries from the stale branch.
This path already reports publish_status => 'stopped', and the PR contract says the frontend retries from that state. Enqueuing wu_async_publish_pending_site here means stale recovery can race a frontend retry against an Action Scheduler retry, while Membership::publish_pending_site() still only has the serialized is_publishing flag as a coarse guard. Pick one retry source here.
🔧 Suggested change
- /*
- * Re-enqueue the async action so Action Scheduler retries
- * the site creation without waiting for the next cron tick.
- */
- wu_enqueue_async_action('wu_async_publish_pending_site', ['membership_id' => $membership->get_id()], 'membership');
-
wp_send_json(['publish_status' => 'stopped']);📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| /* | |
| * Re-enqueue the async action so Action Scheduler retries | |
| * the site creation without waiting for the next cron tick. | |
| */ | |
| wu_enqueue_async_action('wu_async_publish_pending_site', ['membership_id' => $membership->get_id()], 'membership'); | |
| wp_send_json(['publish_status' => 'stopped']); | |
| wp_send_json(['publish_status' => 'stopped']); |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@inc/managers/class-membership-manager.php` around lines 221 - 227, The code
currently enqueues wu_enqueue_async_action('wu_async_publish_pending_site', ...)
and then returns wp_send_json(['publish_status' => 'stopped']), creating two
competing retry sources; remove the Action Scheduler enqueue here so only the
frontend retry (publish_status => 'stopped') is relied on, or alternatively gate
the enqueue behind a check that ensures Membership::publish_pending_site() won't
be retried by both sources (e.g., consult the serialized is_publishing flag or a
new marker before calling wu_enqueue_async_action). Update the block containing
wu_enqueue_async_action and wp_send_json to either drop the enqueue call
entirely or add the guard so only a single retry path is used.
|
Performance Test Results Performance test results for 9af2e77 are in 🛎️! Note: the numbers in parentheses show the difference to the previous (baseline) test run. Differences below 2% or 0.5 in absolute values are not shown. URL:
|
🔨 Build Complete - Ready for Testing!📦 Download Build Artifact (Recommended)Download the zip build, upload to WordPress and test:
🌐 Test in WordPress Playground (Very Experimental)Click the link below to instantly test this PR in your browser - no installation needed! Login credentials: |
SummaryFixes the infinite "Creating" spinner on the thank-you page when the site creation process is killed mid-execution.
Merged via PR #792 to main. aidevops.sh v3.6.235 spent 7m on this as a headless bash routine. |
Summary
Fixes the infinite "Creating" spinner on the thank-you page when the site creation process is killed mid-execution.
Root cause:
publish_pending_site()setsis_publishing=trueon the pending site object and saves it to membership meta. If the PHP process dies (OOM, timeout, server restart) after the flag is set but before the site creation completes or error handlers run, the flag staystruepermanently. The AJAX poll handler (wu_check_pending_site_created) returnsrunningforever, and the Action Scheduler retry bails out because it sees the flag and assumes another process is already handling it.Fix:
publishing_started_attimestamp to the Site model, automatically recorded whenset_publishing(true)is calledis_publishing_stale($timeout)method — returns true when publishing has been running longer than the timeout (default 5 minutes)check_pending_site_created()now detects stale state, resets the flag, re-enqueues the async action, and returnsstoppedso the JS can retryis_publishingis true, since the process that set it is clearly goneFiles changed:
inc/models/class-site.php— new property, getter, and staleness check methodinc/managers/class-membership-manager.php— staleness detection in AJAX handlertests/WP_Ultimo/Models/Site_Test.php— 7 new test cases for the staleness logicTesting instructions:
Summary by CodeRabbit
Release Notes
New Features
Bug Fixes
Tests