Skip to content

visualizer_schedule_refresh_db remains missing after Visualizer reactivation #1384

Closed

Description

@pirate-bot

Summary

Visualizer's recurring database-refresh action can remain absent after the plugin is deactivated and reactivated. Reactivation is expected to register visualizer_schedule_refresh_db, as documented, but the reported installation still has no scheduled action afterward. Database-backed charts therefore lack their recurring refresh trigger and may remain stale until manually refreshed.

Customer context

  • Product / area: Visualizer scheduled database refresh
  • Version: Visualizer 4.0.8; Visualizer Pro 2.0.2
  • Environment: WordPress 7.1.1; PHP 8.3.24; single-site status not explicitly confirmed
  • Integration / third party: Bundled Action Scheduler 3.9.3
  • Reported error / symptom: visualizer_schedule_refresh_db is missing after a deactivate/reactivate cycle; no scheduling error appears in the available Visualizer log
  • Impact: Scheduled database-chart refreshes have no recurring trigger
  • Integrity: Diagnostics reported that the installed free and Pro plugin files match their official releases

Reproduction notes

  1. Use Visualizer 4.0.8 with Visualizer Pro 2.0.2 and a database chart that depends on scheduled refreshes.
  2. Observe that visualizer_schedule_refresh_db is absent under Tools > Scheduled Actions.
  3. Deactivate and reactivate Visualizer once, following the product documentation.
  4. Return to Tools > Scheduled Actions and search for the hook.
  5. Reported result: the action remains missing while other WordPress and plugin scheduled tasks work.

This is a customer-verified runtime reproduction. Repository inspection confirms a lifecycle path that can leave both schedulers empty, but the exact Action Scheduler state that triggered this installation's failure was not captured.

Diagnosis

Conclusion

The released lifecycle code has a confirmed gap that can produce and preserve the reported state. On the Action Scheduler path, Visualizer checks only whether a next action is reported, does not inspect the result of recurring-action creation, clears the WP-Cron fallback, and returns. If registration yields no usable action, both scheduling systems can be empty. Ordinary requests do not recreate the action, and the upgrade path runs only when a legacy WP-Cron event exists. The customer's intact 4.0.8 installation remained without the action after the documented reactivation procedure.

Where this likely occurs

  • classes/Visualizer/Module/Setup.php — Visualizer_Module_Setup::__construct() lines 42-58 registers activation/deactivation and the refresh callback but no recurring-action recovery hook.
  • classes/Visualizer/Module/Setup.php — Visualizer_Module_Setup::activate_on_site() lines 211-218 invokes recurring-action registration during activation.
  • classes/Visualizer/Module/Setup.php — Visualizer_Module_Setup::schedule_refresh_db_action() lines 486-504 calls as_next_scheduled_action(), conditionally calls as_schedule_recurring_action(), then clears the WP-Cron event without checking whether a usable Action Scheduler record was created.
  • classes/Visualizer/Module/Setup.php — Visualizer_Module_Setup::unschedule_refresh_db_action() lines 509-516 removes both Action Scheduler and WP-Cron registrations during deactivation.
  • classes/Visualizer/Module/Upgrade.php — Visualizer_Module_Upgrade::upgrade() lines 18-40 invokes migration only when wp_next_scheduled() finds a legacy event, leaving the both-missing state untouched.
  • classes/Visualizer/Module/Upgrade.php — Visualizer_Module_Upgrade::migrate_action_scheduler() lines 86-103 similarly clears WP-Cron after attempting Action Scheduler registration without validating the resulting action.
  • index.php — visualizer_launch() lines 148-157 loads the bundled Action Scheduler entry point when the release artifact contains it.
  • Commit bc14d4b8 introduced the Action Scheduler migration after v3.11.15; the affected behavior is present in released tag v4.0.8. This establishes the code history but does not by itself prove the customer's exact failure is a regression.

Engineering notes

  • The free plugin owns visualizer_schedule_refresh_db; the Pro add-on manages a separate visualizer_schedule_import action and does not override this lifecycle.
  • Action Scheduler 3.9.3 exposes a recurring-action assurance mechanism, but no corresponding Visualizer registration was found in v4.0.8.
  • Action Scheduler's documented API indicates scheduling calls can return a zero action ID when creation fails. The release path does not distinguish that outcome before removing the fallback.
  • An exact storage-level failure or stale Action Scheduler status has not been captured from the affected installation, so the immediate runtime trigger remains unknown.
  • Open issue Action Scheduler async queue crashes on WordPress 5.3 with wpdb::db_server_info() error #1361 was read and rejected as a duplicate: it concerns a wpdb::db_server_info() fatal on WordPress 5.3, not a missing action on WordPress 7.1.1.
  • Merged commit 1880fdd8 is not in a release tag and adds recovery only when Action Scheduler is unavailable; its inspected branch returns early when Action Scheduler is usable, so it does not establish that this WordPress 7.1.1 report is already fixed.

Test coverage status

tests/test-import.php checks that the custom ten-minute interval exists, and tests/test-schedule.php covers scheduled import behavior. No relevant coverage was found during inspection for activation/deactivation registration, failed Action Scheduler creation, migration with both schedulers empty, or recovery of a missing visualizer_schedule_refresh_db action. The inspected Visualizer Pro scheduler tests concern the separate import action.

What to verify or explore next

  • Reproduce with released Visualizer 4.0.8 and Action Scheduler 3.9.3 by removing all visualizer_schedule_refresh_db records, then running the documented deactivate/reactivate sequence.
  • Inspect all Action Scheduler statuses and logs for the Visualizer group immediately before and after reactivation.
  • Capture the return value and resulting stored record from the recurring-action registration call during activation.
  • Run activation, deactivation, migration, and both-missing recovery scenarios on single-site and multisite installations.
  • Confirm behavior when another active plugin supplies a different Action Scheduler version.

Unknowns / follow-up

  • The affected site's full Action Scheduler status inventory and system information were not available.
  • It is unknown whether a stale, failed, canceled, or in-progress record influenced the next-action lookup.
  • No local runtime reproduction was performed because the checkout lacks the built vendor/ directory and a matching WordPress test environment.

Confidence

Confidence: 88/100

The affected released code can leave the recurring refresh action absent: it does not verify Action Scheduler registration succeeded, clears the WP-Cron fallback on the Action Scheduler path, and has no recovery check when both records are missing. The customer reproduced the missing action after the documented reactivation procedure with release files verified intact.


Source: HelpScout #3456322130
Generated by bug-report-triage (ID: bug-report-triage_6aaf4c4cab58b6.52292839)

Activity

  1. added theissue type on Sep 20, 2026
  2. self-assigned this
    on Sep 21, 2026
  3. milicavs commented on Sep 21, 2026

    @milicavs

    Update after hands-on investigation on the reporting site (HelpScout 3456322130). The original premise of this issue needs correcting, but a real defect in the same area was confirmed and reproduced live.

    Correction

    Reactivation DID restore visualizer_schedule_refresh_db. The site's Action Scheduler data shows the action created at the customer's reactivation (2026-09-19 18:13:38 UTC) and completing every 10 minutes since (238 records at the time of checking). The customer believed it was still missing because they checked WP Crontrol's Cron Events, where the task no longer appears after the WP-Cron to Action Scheduler migration. The docs article for the scheduled database refresh should be updated to point at Tools > Scheduled Actions instead.

    Confirmed defect: a killed run permanently ends the recurring chain

    What actually broke on this site, verified live:

    1. Under Action Scheduler, the next occurrence of a recurring action is only scheduled when the current run reaches schedule_next_instance(). If PHP dies mid run (host kill, fatal, timeout), AS marks the action failed after 300s in-progress and no new occurrence is ever created. Both visualizer_schedule_refresh_db (free) and visualizer_schedule_import (Pro) stop permanently and silently.
    2. Under the previous WP-Cron implementation the recurrence was stored up front, so a killed run simply retried 10 minutes later. The site's history shows import runs had been dying mid run for a long time and the system limped along invisibly. The 4.0.x migration to Action Scheduler turned the same routine kills into a permanent stop, which is when the customer noticed.
    3. There is no recovery path: Visualizer_Module_Upgrade::upgrade() only migrates when a legacy WP-Cron event exists, and nothing at request time checks whether the recurring action is still scheduled.

    Recommended fix

    Hook Action Scheduler 3.9.3's daily action_scheduler_ensure_recurring_actions hook (added for exactly this scenario) and re-register the action when as_next_scheduled_action() returns false:

    add_action( 'action_scheduler_ensure_recurring_actions', function () {
        if ( false === as_next_scheduled_action( 'visualizer_schedule_refresh_db', array(), 'visualizer' ) ) {
            // re-register with the configured interval
        }
    } );

    The same applies to visualizer_schedule_import in Pro. Additionally, schedule_refresh_db_action() should check the return value of as_schedule_recurring_action() (it returns 0 on failure) before clearing the WP-Cron fallback.

    Two further Pro-side defects found during the same investigation (unbounded backlog processing in one run, and interval -1 making charts due on every run) are filed in the Pro repo.

    Site remediated with a watchdog snippet re-registering both actions; verified working on the customer site 2026-09-21.

  4. milicavs commented on Sep 22, 2026

    @milicavs

    🤖 Automated QA Repro Steps

    Database charts refresh on a recurring 10-minute schedule. If one of those runs is cut off mid-flight — a host kill, a PHP timeout, a fatal — the schedule stops for good: no further run is ever created, database charts silently go stale, and nothing in the UI reports it. (The title's premise was corrected during investigation: reactivation does restore the schedule. The customer was looking at WP Crontrol → Cron Events, where the task no longer appears since the move to Action Scheduler — it lives under Tools → Scheduled Actions now.)

    This can't be triggered through normal use; it needs a run to die mid-flight, so the snippet below kills one the way a host would.

    Requires: the Code Snippets plugin, and at least one chart built from a database query.

    Reproduce on Visualizer 4.0.8:

    1. Go to Tools → Scheduled Actions → Pending, search visualizer_schedule_refresh_db, and note the one pending action and its ID.
    2. In Code Snippets, add a snippet titled "Kill a Visualizer refresh run", set it to run everywhere, and activate it:
      add_action( 'admin_init', function () {
          if ( empty( $_GET['vis_kill'] ) || ! current_user_can( 'manage_options' ) ) { return; }
          $store = ActionScheduler::store();
          $ids   = $store->query_actions( array( 'hook' => 'visualizer_schedule_refresh_db', 'group' => 'visualizer', 'status' => ActionScheduler_Store::STATUS_PENDING, 'per_page' => 1 ) );
          foreach ( $ids as $id ) { $store->log_execution( $id ); $store->mark_failure( $id ); }
          delete_transient( 'visualizer-refresh-db-checked' );
          wp_die( 'Killed: ' . implode( ',', $ids ) );
      } );
    3. Open /wp-admin/?vis_kill=1 — the page prints the killed action ID.
    4. Open any other wp-admin page, then return to Tools → Scheduled Actions → Pending and search visualizer_schedule_refresh_db again.
    • Bug: nothing pending. It never comes back, however many admin pages you load, and the database charts stop updating from then on.
    • Fixed: one pending visualizer_schedule_refresh_db is back with a new ID, due immediately and repeating every 10 minutes; the chart's data updates again on the next run.
    Edge cases
    • Set Settings → General → Timezone to one west of UTC (e.g. UTC-8), then repeat — the recovered action is due right away, not parked hours ahead.
    • Run the kill twice in a row — it recovers each time, and only ever one pending action exists (never two firing the same refresh).
    • Deactivate and reactivate Visualizer — exactly one pending action afterwards, and no matching entry under WP Crontrol → Cron Events.
    • With Pro active and a scheduled import, visualizer_schedule_import is a separate Pro-owned action and is not covered by this fix — don't treat it as a failure here.

    Fix: #1385 (open)

  5. pirate-bot commented on Sep 25, 2026

    @pirate-bot
    ContributorAuthor

    QA agent — 🟡 Needs human QA · Killed database-refresh runs recover and update charts; failed scheduling retains a working fallback.

    A simulated killed refresh left no successor, then an ordinary admin page restored one recurring action; running it updated the database chart and its next-refresh time. Daily assurance, recovery west of UTC, repeated kills, and fallback after Action Scheduler refused a new action all behaved as expected. Documentation about where to find scheduled actions and the separate Pro import scheduler still need their own follow-up.

    Please still try

    1. Update and verify the database-refresh documentation points readers to Tools > Scheduled Actions, not WP Crontrol's Cron Events; issue visualizer_schedule_refresh_db remains missing after Visualizer reactivation #1384 requests this, but PR fix: recover the database refresh chain a killed run ends #1385 does not change documentation.
    2. Try killed-run recovery for the separate Pro-owned visualizer_schedule_import hook after its Pro-side change is available; PR fix: recover the database refresh chain a killed run ends #1385 explicitly does not implement that hook.
    3. Try simultaneous requests racing to register the missing refresh action; the repeated-kill journey verified sequential uniqueness, not an actual concurrent race.
    4. Try an actual host-terminated run through Action Scheduler's five-minute queue-cleaner transition and a natural daily cron tick on a low-traffic site; this run simulated failure and explicitly invoked the assurance hook.
    5. Try multisite activation and a site running a different Action Scheduler version, neither of which was exercised here.
    6. Check whether codeinwp/docs-site#2343 is required for this issue; QA excluded it because no issue link could be verified.
    Checks (9 passed)
    • ✅ A fresh activation presents exactly one pending Visualizer database-refresh action repeating every 10 minutes in Tools > Scheduled Actions, and no competing WP-Cron event.
    • ✅ A simulated killed refresh occurrence is marked failed and leaves no pending successor before recovery.
    • ✅ After a killed run and expired check window, opening an ordinary admin page restores exactly one pending database-refresh action with a new ID, due immediately and recurring every 10 minutes, without reactivation.
    • ✅ Executing the recovered database-refresh occurrence updates a due database-backed chart's stored values and next-refresh time, and the new values are visible after reload.
    • ✅ Action Scheduler's daily recurring-action assurance restores one missing refresh action even while the 300-second per-request throttle is active.
    • ✅ With a timezone west of UTC, recovery creates a pending refresh due now rather than hours in the future.
    • ✅ Two consecutive simulated killed refresh occurrences each recover on a subsequent admin request, never leaving more than one pending action.
    • ✅ When Action Scheduler refuses recurring creation during deactivate/reactivate, Visualizer activates without an error and keeps one functioning 10-minute WP-Cron fallback rather than leaving both schedulers empty.
    • ✅ After the refusal is removed and an ordinary admin request runs, the WP-Cron fallback is replaced by exactly one pending Action Scheduler refresh action, with no matching WP-Cron event.

    Ignored PRs: codeinwp/docs-site#2343 (no verifiable link to the issue).

    Full report, evidence and session trail

  6. kushh23 commented on Sep 25, 2026

    @kushh23
    Contributor

    🧪 Test in Playground

    Link Build Bot check
    Reproduce the bug Visualizer 4.0.8 (released) ✅ Reproduced: after the interrupted run, the Pending tab lists no visualizer_schedule_refresh_db action, and it stays missing on the next page loads
    Verify the fix PR #1385 build 02d9630 ✅ Fixed: the Pending tab lists a new visualizer_schedule_refresh_db action (every 10 minutes) on the first admin page load

    Setup: Visualizer's database-refresh action is marked failed, like a run killed mid-flight by the host. Lands on Tools → Scheduled Actions → Pending, filtered to visualizer_schedule_refresh_db. Tools → QA Logs shows debug.log.
    Try: compare the Pending list on both links, then check the Failed tab: both show the one interrupted run.

  7. pirate-bot commented on Sep 30, 2026

    @pirate-bot
    ContributorAuthor

    🎉 This issue has been resolved in version 4.0.9 🎉

    The release is available on GitHub release

    Your semantic-release bot 📦🚀

  8. added
    releasedIndicate that an issue has been resolved and released in a particular version of the product.
    on Sep 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bug-reportbug-report-triagecustomer reportIndicates the request came from a customer.releasedIndicate that an issue has been resolved and released in a particular version of the product.

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions