Skip to main content

Caching Architecture

Scottsdale Mint uses a multi-layer caching strategy designed for a high-traffic precious metals store with real-time pricing constraints.


Caching Layersโ€‹

User Request
โ”‚
โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ Layer 1: CloudFront CDN โ”‚ โ† Static assets, product pages (TTL: minutes to hours)
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ”‚ (cache miss or bypass)
โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ Layer 2: WordPress/Lambda โ”‚ โ† PHP page generation
โ”‚ โ”‚
โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚
โ”‚ โ”‚ Layer 2a: Valkey โ”‚ โ”‚ โ† Object cache (WP transients, DB query results, sessions)
โ”‚ โ”‚ Redis Object Cache โ”‚ โ”‚
โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ”‚ (object cache miss)
โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ Layer 3: Aurora MySQL โ”‚ โ† Database (read replica)
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜


Layer 1: CloudFront CDNโ€‹

What Is Cachedโ€‹

  • Product pages, category pages, and blog posts (HTML responses)
  • Static assets: CSS, JavaScript, fonts, images in /uploads/
  • Processed images: CloudFront performs on-the-fly image resizing

Cache Invalidationโ€‹

CloudFront cache is invalidated automatically by:

  • Ymir after a new deployment
  • The W Rocket / Perfmatters integration (plugin fires CloudFront invalidation)
  • Price update endpoint: invalidates product page cache after price changes

CloudFront is configured to pass these cookies to Lambda (they vary the cache key):

CookiePurpose
woocommerce_cart_hashIdentifies cart state; triggers cart-aware responses
woocommerce_items_in_cartWhether the cart has items
woocommerce_recently_viewedRecently viewed products
wp_woocommerce_session_*WooCommerce session data (wildcard)

Any request with a WooCommerce session cookie will bypass CDN caching for dynamic content.

Never-Cached Pathsโ€‹

These paths always pass through to Lambda โ€” CloudFront never caches them:

  • /cart โ€” Shopping cart
  • /checkout โ€” Checkout page
  • /my-account โ€” Customer account pages
  • /uploads/elementor/* โ€” Elementor builder assets
  • /addons โ€” Add-on products

Layer 2a: Valkey / Redis Object Cacheโ€‹

Plugin: Object Cache Pro (with object-cache.php drop-in) Client: Relay PHP extension (RESP3 protocol support)

Production Configurationโ€‹

WP_REDIS_CLIENT     = 'relay'
WP_REDIS_COMPRESSION = 'zstd' // Zstandard โ€” fast, high ratio
WP_REDIS_IGBINARY = true // igbinary binary serializer (compact)
WP_REDIS_HOST = [from YMIR_REDIS_ENDPOINT]

Local Configurationโ€‹

WP_REDIS_CLIENT=phpredis
WP_REDIS_COMPRESSION=none
WP_REDIS_SERIALIZER=php

Advanced Redis Settings (from config/application.php)โ€‹

SettingValuePurpose
split_alloptionsenabledSplits WordPress alloptions cache into individual keys to prevent cache stampedes
prefetchdisabledAvoids prefetching all alloptions on every request
network_flushsite-levelFor single-site; flushes only the current site's keys

What Is Cached in Redisโ€‹

Cache GroupContents
WordPress transientsTemporary API responses, computed values (TTL-based)
WooCommerce sessionsActive customer sessions, cart data
WP option valuesAll get_option() calls cached in Redis
Database query resultsWP_Query and WP_Term_Query results
User metaFrequently accessed user metadata
Product stock countsReserved stock, available quantities
Pricing cachesuma_pricing_cache โ€” spot price data

Product Meta TTL for Price Freshnessโ€‹

Scottsdale Mint now applies a custom TTL for Redis entries in the WordPress post_meta and WooCommerce products cache group when the key is a numeric product post ID.

  • Hook: suma_object_cache_expire
  • Integration class: Suma\Integration\ObjectCache
  • Method: set_product_meta_cache_expire()
  • Behavior: returns 60 seconds for product post_meta, falls back to default TTL for everything else

This creates a hard one-minute expiration window for cached WooCommerce product meta so price-related metadata cannot remain stale longer than one pricing cycle.

The suma_object_cache_expire hook, is available because Scottsdale Mint applies a custom patch to the plugin:

  • Patch file: patches/0001-Dev-object-cache-pro-add-expire-filter-hook.patch
  • Apply command: patch -l -p1 < patches/0001-Dev-object-cache-pro-add-expire-filter-hook.patch
  • Patched class: web/app/plugins/object-cache-pro/src/ObjectCaches/PhpRedisObjectCache.php

The patch adds apply_filters( 'suma_object_cache_expire', ... ) before Redis writes in key write paths (add, replace, set, and setMultiple behavior), allowing runtime TTL overrides per cache group/key/value.

Without this patch, the Suma\Integration\ObjectCache TTL filter would never run and product post_meta entries would continue using default Object Cache Pro expiration behavior.

Cache Invalidationโ€‹

  • Full flush: wp cache flush (via WP-CLI or /wp-json/suma/v1/utils/clear_cache)
  • Per-object: Automatically invalidated when posts/options are updated
  • Price updates: Price update endpoint flushes product-specific cache keys after price changes

Accessing Remote Redis (Valkey) Cachingโ€‹

Follow these instructions to safely securely connect and inspect Production, Staging, or Dev remote caching instances using your local Windows/WSL development environment.

Step 1: Establish the Secure SSH Tunnelโ€‹

Run the following tunnel command from your WSL command line interface:

Ymir cache:tunnel

You will be prompted with a choice between the Production and Dev remote servers. Select the server environment you wish to inspect.

Step 2: Install Another Redis Desktop Manager (ARDM)โ€‹

Open Windows Terminal as an Administrator and install the desktop client via winget:

winget install qishibo.AnotherRedisDesktopManager

Step 3: Install PHP Dependencies in Herdโ€‹

Because remote data payload structures utilize igbinary serialization and zstd compression, your local environment requires specific PHP 8.4 binaries to successfully extract and translate the cache values.

  1. Ensure PHP 8.4 is fully active in your local Laravel Herd installation.
  2. Download the required extension components: PHP 8.4 Redis Extensions ZIP.
  3. Navigate to the following local folder path and extract both .dll files (php_igbinary.dll and php_zstd.dll) inside it:
%USERPROFILE%\.config\herd\bin\php84\ext

  1. Open the PHP configuration file %USERPROFILE%\.config\herd\bin\php84\php.ini and append the following structural definitions to the absolute bottom of the file:
extension=C:\Users\<username>\.config\herd\bin\php84\ext\php_igbinary.dll
extension=C:\Users\<username>\.config\herd\bin\php84\ext\php_zstd.dll

IMPORTANT

Explicitly swap out <username> for your active Windows profile username. Shared system notation mappings like %USERPROFILE% do not resolve when parsing initialization rules in php.ini.

  1. Restart Laravel Herd services to load the newly introduced libraries.

Step 4: Map the Decoding Scriptโ€‹

  1. Navigate to the root directory of your local Z: Drive network path.
  2. Create a subfolder named ardm.
  3. Download the decoder logic: redis_decoder.php.
  4. Save the file directly into your newly configured directory path: Z:\ardm\redis_decoder.php.

Step 5: Configure the Client Connectionโ€‹

  1. Launch Another Redis Desktop Manager.
  2. Click the + New Connection button and fill out the mapping values:
  • Host: localhost
  • Port: 6378
  • Auth: None (Leave blank)
  • Connection Name: Scottsdale Mint
  1. Click OK. Upon a successful initialization, your workspace sidebar will list Scottsdale Mint.
  2. Double-click the instance node to view the database index partitions. Select the numeric database block that aligns with your active environment inspection:
  • DB 0: Production
  • DB 1: Staging
  • DB 2: Development

Step 6: Assign Custom Deserialization Rulesโ€‹

By default, values inside the database are stored compressed, generating binary Hex format reads. Map the custom formatter extension to display data cleanly:

  1. Click on any active key parameter inside the workspace database tree.
  2. Locate the format management dropdown filter element situated immediately above the main body value block window (this option natively defaults to Hex).
  3. Expand this selection control layout list, navigate to the bottom area, and select Customize.
  4. Click New and submit the configuration properties:
  • Name: Zstd + Igbinary
  • Command: C:\Users\<username>\.config\herd\bin\php84\php.exe
  • Params: Z:\ardm\redis_decoder.php {HEX} (Ensure you change <username> to match your real Windows system user identity string).
  1. Confirm the action. Now, toggling the format mode view option value filter over to Zstd + Igbinary will correctly decode and print complex object schemas in readable configurations.

Performance Toolsโ€‹

Perfmattersโ€‹

Plugin: perfmatters (with MU-plugin override a-suma-perfmatters-filters.php)

Features used:

  • Script/style management per page (disable unnecessary scripts)
  • Database cleanup (auto-draft posts, transients, revisions)
  • Lazy loading for images
  • Google Fonts hosting locally (GDPR)
  • Cache path override: uploads/perfmatters/cache/ (set in MU plugin)

Scalability Proโ€‹

Plugin: scalability-pro

Features:

  • Deferred term count updates (prevents lock contention on high-traffic stores)
  • Query optimization for large WooCommerce product catalogs

Caching and Pricingโ€‹

Precious metals prices change every minute. The cache strategy accounts for this:

  1. Product pages are cached at CloudFront. When the Laravel middleware calls the price update endpoint:
  • Product prices are updated in Aurora
  • Redis object cache for those products is flushed
  • CloudFront cache for those product URLs is invalidated
  • Product post_meta cache entries also expire after 60 seconds even if a targeted flush is missed
  1. Cart pricing is always real-time (cart page bypasses CloudFront)
  2. Spot price widget (NFusion live chart) fetches directly from NFusion CDN โ€” not cached by WordPress

In practice, this means customers moving from product page to cart/checkout are far less likely to encounter stale cached pricing when NFusion-driven updates run every minute.


Disabling Cache for Developmentโ€‹

In .env:

WP_CACHE=false

This disables the Redis object cache drop-in. Useful for development to see fresh database queries.

caution

Never set WP_CACHE=false on staging or production โ€” it will dramatically increase Aurora database load.