6.7 KiB
FT546 WMS Shadow-Only Design
Goal
Create a clean field-test branch directly from origin/main that runs the Java storage algorithm only as an observer. The existing Legacy WMS stored procedures remain the sole owners of inbound and outbound decisions and business writes.
Safety invariants
- The branch is based on
origin/mainand contains no license, UI, TLS, tidy, replay, PDA, WCS callback, or ACTIVE workflow integration changes. - Legacy stored procedures are called exactly once with the same inputs and their return values remain authoritative.
- Shadow planning is submitted immediately before Legacy allocation to maximize pre-decision observation, but runs only on a dedicated background worker in a separate
REQUIRES_NEW,READ_UNCOMMITTEDtransaction with a configurable timeout. The Legacy thread never waits for planning or comparison. - A shadow exception, timeout, missing optional input, missing algorithm object, or comparison logging failure is caught and logged; it cannot skip, replace, roll back, or rewrite the Legacy result.
- No ACTIVE entry point is exposed by
ruoyi-admin. Startup rejects any algorithm mode other thanSHADOWwhen shadow observation is enabled. - Shadow mode writes only
alg.*read-model and diagnostic objects. It never calls reservation, tidy, deep-workflow, replay, move-completion, or other procedures that write WMS business tables. - Shadow observation is disabled by default and must be enabled explicitly in the IDEA Run Configuration.
- At most one shadow observation cycle runs per JVM. The dedicated executor has one daemon worker, zero queue capacity, and rejects busy submissions immediately without running work on the Legacy thread.
Architecture
The existing fortucky-algorithm planner and JDBC read model are reused as an internal dependency. A new ruoyi-admin shadow adapter owns the integration boundary:
ShadowObservationPropertiescontrols enablement, warehouse fallback, and timeout.ShadowSafetyGuardvalidates the effective mode at startup.ShadowObservationGatewaysubmits fail-open inbound/outbound planning to a dedicated single-thread, zero-queue executor and returns a nonblocking completion token.- Legacy services submit the observation immediately before their existing stored procedure, execute the original Legacy code unchanged, then complete the in-memory token with the Legacy result. The background worker performs comparison only if both results arrive within the configured observation deadline.
There are no algorithm controllers, ACTIVE schedulers, workflow callbacks, reservation calls, or changes to the frontend.
Data flow
Inbound
- Load the same inbound job that
origin/mainalready loads. - Submit shadow planning to the background worker without waiting. Busy/rejected submissions become no-op completion tokens.
- Invoke the existing
allotInJobSpacestored procedure exactly once. - Reload and return the Legacy job exactly as
origin/maindoes. - Complete the in-memory token with the Legacy location; the background worker logs the comparison if planning and Legacy results both complete before the observation deadline.
Outbound
- Before each existing automatic or manual Legacy allocation call, submit a background observation without waiting.
- Missing project/stock data is recorded as a shadow rejection; it never blocks the Legacy procedure.
- Invoke the original
autoAllotormanualAllotprocedure exactly once. - Preserve the original success/warning response construction.
- Complete the in-memory token with the Legacy procedure code; comparison logging remains background-only.
Transaction and failure isolation
Shadow planning uses TransactionTemplate with PROPAGATION_REQUIRES_NEW, ISOLATION_READ_UNCOMMITTED, read-model writes enabled, and a short timeout. A dedicated ThreadPoolExecutor has one daemon worker, a SynchronousQueue, and AbortPolicy: no task queues, rejection never falls back to the Legacy caller, and at most one observation cycle is active per JVM. The submitted task plans, waits only in the background for the Legacy completion token, and writes the comparison. Runtime failures, rejection, interruption, and observation-deadline expiry are caught in the gateway.
Because the Legacy call starts immediately after submission, thread scheduling and database timing can let a shadow read overlap or follow the Legacy write. This is an accepted data-quality limitation of zero-wait shadowing. Shadow results are diagnostic only and must not be interpreted as a guaranteed pre-Legacy snapshot.
The integration never queries alg.tidy_mode and never uses an update lock for admission control.
Shadow database package
install-shadow.sql creates only:
- policy/read-model/diagnostic tables required by inbound and outbound planning;
- read-only views over WMS business data;
- topology, snapshot, lane-state, full-refresh, and decision-log support;
- no triggers on any Legacy WMS table and no dirty-lane queue;
- initial read-model synchronization.
It excludes tidy, replay, reservation mutation procedures, deep workflow, outbound workflow, WCS completion, PDA callback, and any stored procedure that inserts, updates, or deletes WMS business rows.
Installation refuses to run if the alg schema already exists. It creates an alg.shadow_package_manifest row with the exact package id and version before creating the remaining objects.
uninstall-shadow.sql refuses to run unless the manifest id/version matches and every top-level object in alg is on the package allow-list. Only then does it remove the shadow-owned objects and schema. It never modifies WMS business rows. Operators must export alg.decision_log before uninstalling.
Configuration
The IDEA field-test configuration sets:
FORTUCKY_SHADOW_ENABLED=true
FORTUCKY_ALGORITHM_MODE=SHADOW
FORTUCKY_ALGORITHM_DATABASE_WRITES_ENABLED=true
FORTUCKY_ALGORITHM_WAREHOUSE_ID=<field warehouse>
FORTUCKY_SHADOW_TIMEOUT_SECONDS=3
Replay variables remain unset. The stable origin/main Run Configuration is kept in a separate source directory for immediate rollback.
Verification
Automated tests prove:
- observer failure still invokes Legacy exactly once;
- missing project/stock input still invokes Legacy exactly once;
- Legacy result and response structure remain authoritative;
- SHADOW configuration rejects ACTIVE mode;
- shadow SQL contains only allow-listed
algobjects, no triggers, and no WMS business-table DML; - install/uninstall object lists are symmetrical;
- existing project tests and packaging still succeed.
Field verification compares inbound/outbound shadow logs with Legacy results, monitors SQL latency and locks, and stops immediately if normal WMS behavior differs from origin/main.