Skip to main content

Mage2Plenty v3.10 - Self-Healing Stock-Drift Detection & Faster Incremental Sync

· 7 min read
Soft Commerce Team
Mage2Plenty Development Team

Mage2Plenty v3.10 adds an automatic stock-drift detection, auto-fix and weekly report suite that keeps Magento and PlentyONE physical quantities in agreement, eliminates plenty_stock_export_queue deadlocks under concurrent load, and makes incremental sync noticeably faster by indexing the collected_at watermark on every mirror table. It also hardens routine maintenance with batched, memory-safe cleanup across history, queue and orphaned stock.

Stock Accuracy

Self-healing physical-drift detection

Physical stock can quietly diverge between systems — a missed event, a manual edit, a failed batch — and the gap usually only surfaces when a customer orders something that isn't really there. v3.10 introduces a stock-consistency suite that finds and closes those gaps on its own.

  • DriftInspector is a read-only, direction-agnostic detector that compares Magento physical (inventory_source_item.quantity) against PlentyONE physical (plenty_stock_entity.stock_physical) for every mapped source/warehouse pair.
  • An hourly tracker (plenty_stock_drift_log_sync, default 35 * * * *) records each discrepancy's persistence in the new plenty_stock_drift_log table and attempts a direction-aware auto-fix (re-collect-then-re-pend for import, enqueue for export), so transient drift self-heals before anyone notices.
  • A weekly report (plenty_stock_drift_report, default Monday 06:00) escalates only the drift that persisted past a configurable threshold (default 24 hours) — so genuinely stuck SKUs reach you, and a clean week sends nothing.

The report is delivered through a new stock physical-drift report email in the notification module, sent to your configured notification recipients.

On-demand drift report

For ad-hoc checks there's a read-only CLI that runs the same inspection without changing anything:

# Inspect the import-primary scope (import profile, plus export when active)
bin/magento plenty:stock:drift:report

# Inspect a single profile
bin/magento plenty:stock:drift:report --profile=<id>

Orphan & stale stock cleanup

Two new maintenance commands (and their crons) keep plenty_stock_entity free of rows that can otherwise inflate warehouse totals:

# Remove rows whose variation no longer exists in PlentyONE (age-guarded)
bin/magento plenty:stock:cleanup:orphan

# Remove rows for warehouses no longer in the local PlentyONE warehouse config
bin/magento plenty:stock:cleanup:warehouse

The plenty:stock:cleanup:orphan logic is shared with a scheduled plenty_stock_orphan_cleanup cron — disabled by default because it is destructive (enable it once you've confirmed the dry behaviour, with a 14-day retention guard). All stock-maintenance crons — reservation cleanup, export-drift reconcile, drift detection, drift report and orphan cleanup — now live under the same plenty/stock_config/* convention, each with its own enable toggle and schedule so you can turn any of them off independently of stock sync.

Export queue: no more deadlocks

Under heavy concurrent load — the high-volume Plenty stock import, order shipments, admin/CSV saves and the drift reconciler all writing at once — plenty_stock_export_queue could deadlock on its UNIQUE(sku) index, surfacing as SQLSTATE[40001] ... Deadlock found in the logs. v3.10 fixes this at the single shared writer:

  • Deterministic lock ordering — multi-row upserts are sorted by SKU, so every statement locks the unique index in the same order and overlapping batches no longer invert.
  • Safe retry — deadlock/lock-wait retries apply only when the upsert is its own autocommit statement; inside a caller's transaction the error is allowed to propagate so a rolled-back transaction is never partially re-committed.

On top of that, the queue is now gated on the export schedule: when the stock-export schedule is inactive (both the schedule record and the profile schedule status), automatic producers stop enqueueing instead of piling up rows that will never be drained. Explicit CLI and manual actions still bypass the gate, so ad-hoc exports keep working with the schedule switched off.

Performance

Faster incremental sync

Incremental collection asks "what changed since the last run?" by reading the newest collected_at watermark on each PlentyONE mirror table. Until now that lookup scanned and sorted the whole table. v3.10 adds a dedicated collected_at btree index to every mirror table — attribute, category, client, customer, item, log, order, property and stock — and limits the watermark query (GetLastCollectedAt) to a single row.

The result: the per-table "since last run" lookup that drives every scheduled collection is now index-backed instead of a full scan, so collection starts faster and stays fast as catalogues and history grow.

Maintenance & Stability

Batched, memory-safe cleanup

Long-running stores accumulate history, queue and log rows that eventually slow housekeeping down or exhaust memory when purged in one shot. v3.10 adds a shared BatchPurgeTrait in the core module for batched, age-based deletion and applies it across the suite:

  • Profile history cleanup now batches its deletes and indexes created_at.
  • Profile queue cleanup now batches its deletes.
  • A new Magento-deleted item orphan cleanup cron prunes mirror rows for products that no longer exist in Magento.

These keep maintenance jobs bounded and predictable on large installations.

Bug Fixes

  • Image import without Magento_Downloadable — product image import resolves DomainManagerInterface at runtime, but the only binding shipped in Magento_Downloadable. With that module disabled, import failed with "Cannot instantiate interface". The core module now binds it, so image import works regardless of the downloadable module's state.
  • Null manufacturer country id — attribute import no longer fails when a manufacturer has no country id set.

Release Summary

ModuleVersionBumpKey Changes
module-core2.4.1 → 2.5.0minorBatchPurgeTrait for batched DB cleanup; bind DomainManagerInterface so image import works without Magento_Downloadable
module-plenty-stock-profile2.5.0 → 2.6.0minorStock drift detection, auto-fix & weekly report; orphan and deleted-warehouse stock cleanup
module-plenty-item-profile3.4.1 → 3.5.0minorMagento-deleted item orphan cleanup cron; guard null manufacturer country id on import
module-profile-notification2.1.2 → 2.2.0minorStock physical-drift report email
module-plenty-stock2.2.1 → 2.2.2patchPrevent plenty_stock_export_queue deadlocks and gate enqueue on schedule; index collected_at
module-profile-history2.0.1 → 2.0.2patchBatch history cleanup and index created_at
module-profile-queue2.0.1 → 2.0.2patchBatch queue cleanup
module-plenty-profile2.2.1 → 2.2.2patchLimit GetLastCollectedAt watermark query to a single row
Incremental-sync indexingpatchpatchcollected_at index added to attribute, category, client, customer, item, log, order and property mirror tables

The collected_at index ships in each of those module repos individually (module-plenty-attribute 2.0.5, -category 2.2.3, -client 2.1.5, -customer 2.1.4, -item 2.4.3, -log 2.0.3, -order 2.2.1, -property 2.0.6). module-plenty-order-profile (2.7.1) and module-profile-schedule (2.0.4) ship as internal maintenance bumps.

Metapackage: softcommerce/mage2plenty-os 3.9.0 → 3.10.0

Upgrade Guide

composer require softcommerce/mage2plenty-os:^3.10

bin/magento setup:upgrade
bin/magento setup:di:compile
bin/magento cache:flush

This release does ship schema changes — the new plenty_stock_drift_log table and collected_at indexes across the mirror tables — so setup:upgrade will apply them. On very large tables, adding the indexes can take a few moments; plan the upgrade accordingly.

Default-on-upgrade behaviours worth noting:

  • Drift detection and the weekly drift report are enabled by default (hourly tracker, Monday report). Adjust or disable them under Stock Settings on the stock-export profile.
  • Orphan stock cleanup is disabled by default — it is destructive; review and enable it deliberately.
  • Export enqueue is now gated by the stock-export schedule. If you run stock export only via explicit CLI/manual actions (schedule off), nothing changes for you; automatic producers simply stop queueing rows that wouldn't be drained.
  • module-plenty-stock-profile now depends on module-profile-notification for the drift report email.

Resources


Questions about the upgrade? Reach out to us at support@byte8.io.