Documentation · System Requirements

Cron and Background Processing

Purpose

ADP Car Market Hub depends on scheduled background tasks for almost everything that is not a direct user action: it imports vehicles from AutoScout24, processes images asynchronously, cleans up analytics data, refreshes pricing analysis and runs daily data-quality scans. This document explains the cron mechanisms the plugin uses, the differences between WordPress's built-in scheduler and a real server cron, the recurring jobs the plugin schedules, and the operational signals to monitor.

When to use this document

Use this document when you:

  • Decide between WP-Cron and an external server cron for a new dealership site.
  • Configure the cron mode, frequency and secret token in the Import & Limits tab.
  • Wire an external scheduler (Linux cron, hosting cron UI, or a remote pinger) to the plugin's REST cron endpoint.
  • Investigate why imports are not running on schedule, or why image processing is delayed.
  • Audit which recurring jobs the plugin registers and how long their data is retained.

Overview

The plugin's background-processing model has three layers:

  1. A trigger layer that decides when work should start. This can be WordPress's pseudo-cron (driven by site visits to wp-cron.php) or an external server cron that calls either wp-cron.php directly or the plugin's token-secured REST endpoint at /wp-json/as24ci/v1/cron-import.
  2. A scheduler layer that owns the recurring jobs. The plugin registers custom intervals (every 5 minutes, every 6 hours, plus a configurable "every N minutes" interval with a 15-minute floor) and a small set of WP-Cron hooks for imports, the image queue, the AI generation queue, analytics cleanup, pricing analysis and the daily taxonomy scan.
  3. A worker layer that does the actual work. Each WP-Cron hook is bound to a class method (importer, image queue, analytics cleanup, etc.) that uses transient-based locks to prevent overlapping runs and writes status/heartbeat options that the System & Help / Health tab and the dashboard widget read back.

All three import paths — the scheduled WP-Cron hook, the REST cron endpoint and the "Trigger now" admin button — call the same shared runner, so behaviour and locking are identical regardless of trigger.

WordPress cron vs. server cron

The Import & Limits tab exposes two trigger modes; both are supported, but they have very different reliability profiles.

WordPress Cron (default)

  • Driven by visitor traffic. Each request to a WordPress page may spawn wp-cron.php in the background.
  • Works on any host without server access.
  • Becomes unreliable on low-traffic sites: with no visitors there are no cron runs.
  • The plugin still installs all of its hooks; missing runs simply accumulate until the next visit.
  • Driven by the operating system or hosting control-panel scheduler.
  • Independent of website traffic, predictable, and required by the plugin's Health checks for a "fully ready" production status.
  • Recommended setup: 1. Set define( 'DISABLE_WP_CRON', true ); in wp-config.php so visit-driven cron is disabled. 2. Add a server cron entry that calls the plugin's REST endpoint with the secret token. 3. Add a second entry that runs wp-cron.php itself, so non-import recurring jobs (image queue, analytics cleanup, pricing, etc.) still fire.

Switching to Server Cron in the Import & Limits tab hides the WP-Cron schedule fields and reveals the REST trigger URL, the secret token, and copy-ready example commands.

Recurring jobs registered by the plugin

The following WP-Cron hooks are scheduled by the plugin (some only when the related feature is configured). The System & Help tab lists their next scheduled run time so they can be inspected at any moment.

HookPurposeFrequency
as24ci_scheduled_importMain vehicle import runner; calls the AutoScout24 API for each configured seller.Configurable in the Import & Limits tab (hourly, twice daily, daily, every 6 hours, every 5 minutes, or a custom "every N minutes" interval with a minimum of 15 minutes).
as24ci_image_queue_processAsynchronous image worker; downloads remaining vehicle images after the first one is loaded inline during import.Every 5 minutes when the image queue is enabled.
as24ci_daily_cleanupDeletes analytics events older than the configured retention window (default 180 days, minimum 7 days).Daily.
as24ci_pricing_analysis_cronRecomputes the pricing-engine analysis for the inventory.Daily.
as24ci_automated_taxonomy_scanBackground data-quality / taxonomy scan.Frequency configured by the Data Quality module.
as24ci_competitor_watcher_cronLegacy cleanup only; the Competitor Watcher feature has been removed and is not active. The hook name is retained so that any leftover scheduled event from older installations is cleared on plugin deactivation.Not scheduled.
AI generation queue hookAsynchronous AI Assistant generation worker; only scheduled when the AI Assistant is enabled and configured.Driven by the AI Assistant settings.

Activation registers the recurring jobs that should always exist (imports, analytics cleanup, pricing, image queue, AI queue when applicable). Deactivation removes the plugin's WP-Cron entries via wp_clear_scheduled_hook() for each hook above.

Recurring imports

The import runner is shared by all three trigger paths and behaves as follows:

  • Locking. Before doing any work the runner sets a transient (as24ci_cron_import_running) with a TTL of roughly 40 minutes. Subsequent runs that arrive while the lock is held exit cleanly and report that an import is already running. This prevents WP-Cron and a server cron from racing against each other.
  • Per-seller processing. The runner iterates over every configured Seller ID and calls the importer for each one in turn.
  • Vehicles per run. The Import & Limits tab exposes a "Vehicles per Run" cap (0 = no limit). Lowering this value is the primary lever for stability on shared hosting and very large inventories; recommended values are 50–80 for large catalogues.
  • Status persistence. After each run, options are updated with the last run timestamp, the trigger source (wp-cron, rest, manual) and per-seller counts. The dashboard widget and System & Help tab read these options to render last-run information.
  • Optional full sync. When the Full Sync option is enabled, the runner can mark vehicles missing from the latest API response as deleted; this is permanent, so a tested backup strategy is required (see Hosting Requirements).

The Batch-Wizard in the admin UI uses the same importer but processes one vehicle per step from a queued list (transient as24ci_batch_queue), which is useful for very large initial imports on constrained hosts.

Image queue and asynchronous workers

When Enable Image Queue is on (recommended for image-heavy imports):

  • During import only the first image of each vehicle is downloaded synchronously, so the page returns quickly and the cron run completes well within PHP execution-time limits.
  • Remaining image URLs are appended to the image queue (a WordPress option) and processed in batches by the as24ci_image_queue_process hook every 5 minutes.
  • The worker uses its own transient lock (as24ci_image_queue_running, 10-minute TTL) and processes a fixed number of images per batch.
  • A safety limit (the queue size limit constant in Scheduler) caps how large the queue may grow before the plugin logs a warning and forcibly de-duplicates entries.

The AI generation queue follows a similar pattern: AI calls during import are deferred to a queue and processed by an async worker so that import runs are not blocked by the managed Gemini endpoint.

Cleanup and retention routines

  • Analytics retention. Analytics::cleanup_old_data() (hook as24ci_daily_cleanup) deletes analytics rows older than the value in the Analytics retention days setting. The default is 180 days; the minimum enforced in code is 7 days.
  • Log rotation. Plugin logs in wp-content/uploads/as24ci-logs/ are rotated when a single file reaches 10 MB, and rotated files are deleted after 7 days. This is independent of WP-Cron and runs on each log write.
  • Token cache. OAuth access tokens are cached in a transient until shortly before their advertised expires_in. A "Clear Token Cache" tool exists for diagnostics.
  • Vehicle deletions. When the plugin removes a vehicle (Full Sync or manual deletion) it cleans up the related media attachments and meta through a central deletion path.

REST cron endpoint

The token-secured trigger endpoint is registered by Cron_Endpoint:

  • Route: GET /wp-json/as24ci/v1/cron-import
  • Authentication: a 32-character random secret stored in the as24ci_cron_token option. The endpoint accepts the token in two ways:
  • Preferred: Authorization: Bearer <token> HTTP header (keeps the token out of access logs).
  • Fallback: ?token=<token> query parameter.
  • Response codes: 200 on success, 429 when the lock is already held (an import is already running), 403 for missing/invalid tokens, 500 for uncaught exceptions.
  • Side effect: every successful call updates the as24ci_last_external_cron_run option, which the System & Help tab uses to confirm the external cron is alive.
  • A separate, unauthenticated heartbeat is recorded whenever any WordPress URL is hit with ?as24ci_cron=1, which is useful for cheap external pingers that only need to confirm reachability.

The Import & Limits tab generates copy-ready example commands such as:

*/15 * * * * curl -s "https://example.com/wp-json/as24ci/v1/cron-import?token=YOUR_TOKEN" > /dev/null
*/5  * * * * php /var/www/html/wp-cron.php > /dev/null 2>&1

The first entry triggers imports; the second keeps non-import WP-Cron hooks (image queue, analytics cleanup, pricing, etc.) running when DISABLE_WP_CRON is true.

Operational monitoring

The plugin exposes the signals operators need to monitor without any extra tooling:

  • System & Help / Health tab. Lists every plugin cron hook, its next scheduled run, and whether scheduling is currently handled by WP-Cron or by an external server cron. Includes a card that flags DISABLE_WP_CRON as recommended in server-cron mode.
  • Dashboard widget. Shows the most recent import run, the next scheduled import (when WP-Cron is in use), the image-queue depth and the next queue run.
  • Plugin logs. wp-content/uploads/as24ci-logs/ records each cron run, lock acquisition/release, image-queue activity and any HTTP errors. Logs rotate at 10 MB with 7-day retention.
  • Last-run options. as24ci_last_external_cron_run and the corresponding internal options can be checked directly via WP-CLI for scripted alerting.

A simple production setup is:

  • Uptime check on the public archive URL (front-end availability).
  • Uptime check on /wp-json/as24ci/v1/cron-import?token=… returning a 2xx/429 status (cron path reachable and authenticating).
  • Disk-space alert on the wp-content/uploads/ volume (image growth and logs).
  • Optional log-shipping or periodic review of the plugin log directory.

Troubleshooting

  • Imports never run automatically. Confirm the cron mode in the Import & Limits tab. If WP-Cron is selected, low-traffic sites may not fire cron at all — switch to server cron. If server cron is selected, verify that the curl/wget command actually reaches the REST endpoint (HTTP 200 or 429 expected).
  • "An import is already running" responses (HTTP 429). The lock transient is still held from a previous run. Wait for the run to finish, or clear the as24ci_cron_import_running transient if a previous PHP process crashed without releasing the lock. Lower Vehicles per Run to keep individual runs comfortably below the lock TTL.
  • Image queue grows without shrinking. Confirm that wp-cron.php is being executed (in server-cron mode this requires the second cron entry shown above), check the log directory for queue-worker errors, and verify outbound HTTPS to the image hosts (see API, Network and SSL Requirements).
  • Analytics or pricing data not refreshed. These run via WP-Cron daily; if DISABLE_WP_CRON is true and there is no second cron entry calling wp-cron.php, daily jobs will never fire.
  • System & Help tab shows the cron token is not configured. Open the Import & Limits tab, switch to server-cron mode and either let the plugin auto-generate a token or paste your own and save.
  • Token leaked or rotated. Click Regenerate Token in the Import & Limits tab. Update every external scheduler immediately, since the previous token stops working as soon as the new one is saved.
  • Cron runs on staging affect production data. Use a different cron token per environment and consider a different AutoScout24 client when possible (see Hosting Requirements).