b2c-custom-caches

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

B2C Custom Caches

B2C 自定义缓存

Custom caches improve code performance by storing data that is expensive to calculate, takes a long time to retrieve, or is accessed frequently. Caches are defined in JSON files within cartridges and accessed via the Script API.
自定义缓存通过存储计算成本高、检索耗时久或访问频繁的数据来提升代码性能。缓存定义在cartridge内的JSON文件中,可通过Script API进行访问。

When to Use Custom Caches

何时使用自定义缓存

Use CaseExample
Expensive calculationsCheck if any variation product is on sale for base product display
External system responsesCache in-store availability or prices from external APIs
Configuration settingsStore configuration data from JSON files or external sources
Frequently accessed dataProduct attributes, category data, site preferences
使用场景示例
计算成本高的操作为基础商品展示检查是否有变体商品正在促销
外部系统响应缓存来自外部API的门店库存或价格数据
配置设置存储来自JSON文件或外部源的配置数据
频繁访问的数据商品属性、分类数据、站点偏好设置

Limitations

限制条件

ConstraintValue
Total memory per app server~20 MB for all custom caches
Max caches per code version100
Max entry size128 KB
Supported value typesPrimitives, arrays, plain objects,
null
(not
undefined
)
Cross-server syncNone (caches are per-application-server)
约束项取值
每个应用服务器的总内存所有自定义缓存约20 MB
每个代码版本的最大缓存数量100
缓存条目的最大大小128 KB
支持的值类型基本类型、数组、普通对象、
null
(不支持
undefined
跨服务器同步无(缓存为每个应用服务器独立存储)

Defining a Custom Cache

定义自定义缓存

File Structure

文件结构

my_cartridge/
├── package.json       # References caches.json
└── caches.json        # Cache definitions
my_cartridge/
├── package.json       # 引用caches.json
└── caches.json        # 缓存定义文件

package.json

package.json

Add a
caches
entry pointing to the cache definition file:
json
{
  "name": "my_cartridge",
  "caches": "./caches.json"
}
添加
caches
条目指向缓存定义文件:
json
{
  "name": "my_cartridge",
  "caches": "./caches.json"
}

caches.json

caches.json

Define caches with unique IDs and optional expiration:
json
{
  "caches": [
    {
      "id": "ProductAttributeCache"
    },
    {
      "id": "ExternalPriceCache",
      "expireAfterSeconds": 300
    },
    {
      "id": "SiteConfigCache",
      "expireAfterSeconds": 60
    }
  ]
}
PropertyRequiredDescription
id
YesUnique ID across all cartridges in code version
expireAfterSeconds
NoMaximum seconds an entry is retained
使用唯一ID定义缓存,可选择设置过期时间:
json
{
  "caches": [
    {
      "id": "ProductAttributeCache"
    },
    {
      "id": "ExternalPriceCache",
      "expireAfterSeconds": 300
    },
    {
      "id": "SiteConfigCache",
      "expireAfterSeconds": 60
    }
  ]
}
属性是否必填描述
id
在同一代码版本的所有cartridge中需唯一
expireAfterSeconds
缓存条目保留的最大秒数

Using Custom Caches

使用自定义缓存

Script API Classes

Script API 类

ClassDescription
dw.system.CacheMgr
Entry point for accessing defined caches
dw.system.Cache
Cache instance for storing and retrieving entries
描述
dw.system.CacheMgr
访问已定义缓存的入口类
dw.system.Cache
用于存储和检索缓存条目的缓存实例

Basic Usage

基础用法

javascript
var CacheMgr = require('dw/system/CacheMgr');

// Get a defined cache
var cache = CacheMgr.getCache('ProductAttributeCache');

// Get value (returns undefined if not found)
var value = cache.get('myKey');

// Store value directly
cache.put('myKey', { data: 'value' });

// Remove entry
cache.invalidate('myKey');
javascript
var CacheMgr = require('dw/system/CacheMgr');

// 获取已定义的缓存
var cache = CacheMgr.getCache('ProductAttributeCache');

// 获取值(未找到则返回undefined)
var value = cache.get('myKey');

// 直接存储值
cache.put('myKey', { data: 'value' });

// 删除条目
cache.invalidate('myKey');

Recommended Pattern: get with Loader

推荐模式:结合Loader使用get方法

Use
get(key, loader)
to automatically populate the cache on miss:
javascript
var CacheMgr = require('dw/system/CacheMgr');
var Site = require('dw/system/Site');

var cache = CacheMgr.getCache('SiteConfigCache');

// Loader function called only on cache miss
var config = cache.get(Site.current.ID + '_config', function() {
    // Expensive operation - only runs if not cached
    return loadConfigurationFromFile(Site.current);
});
使用
get(key, loader)
在缓存未命中时自动填充缓存:
javascript
var CacheMgr = require('dw/system/CacheMgr');
var Site = require('dw/system/Site');

var cache = CacheMgr.getCache('SiteConfigCache');

// 仅在缓存未命中时调用Loader函数
var config = cache.get(Site.current.ID + '_config', function() {
    // 高成本操作 - 仅在未缓存时执行
    return loadConfigurationFromFile(Site.current);
});

Scoped Cache Keys

带作用域的缓存键

Include scope identifiers in keys to separate entries by context:
javascript
var CacheMgr = require('dw/system/CacheMgr');
var Site = require('dw/system/Site');

var cache = CacheMgr.getCache('ProductCache');

// Site-scoped key
var siteKey = Site.current.ID + '_' + productID;
var productData = cache.get(siteKey, loadProductData);

// Catalog-scoped key
var catalogKey = 'catalog_' + catalogID + '_' + productID;
var catalogData = cache.get(catalogKey, loadCatalogData);

// Locale-scoped key
var localeKey = request.locale + '_' + contentID;
var content = cache.get(localeKey, loadLocalizedContent);
在键中包含作用域标识符,按上下文区分不同条目:
javascript
var CacheMgr = require('dw/system/CacheMgr');
var Site = require('dw/system/Site');

var cache = CacheMgr.getCache('ProductCache');

// 站点作用域的键
var siteKey = Site.current.ID + '_' + productID;
var productData = cache.get(siteKey, loadProductData);

// 目录作用域的键
var catalogKey = 'catalog_' + catalogID + '_' + productID;
var catalogData = cache.get(catalogKey, loadCatalogData);

// 语言环境作用域的键
var localeKey = request.locale + '_' + contentID;
var content = cache.get(localeKey, loadLocalizedContent);

Cache Methods

缓存方法

MethodDescription
get(key)
Returns cached value or
undefined
get(key, loader)
Returns cached value or calls loader, stores result
put(key, value)
Stores value directly (overwrites existing)
invalidate(key)
Removes entry for key
方法描述
get(key)
返回缓存值或
undefined
get(key, loader)
返回缓存值,若未命中则调用loader并存储结果
put(key, value)
直接存储值(覆盖现有条目)
invalidate(key)
删除对应键的条目

Best Practices

最佳实践

Do

建议

  • Use
    get(key, loader)
    pattern for automatic population
  • Include scope (site, catalog, locale) in cache keys
  • Set appropriate
    expireAfterSeconds
    for time-sensitive data
  • Handle cache misses gracefully (data may be evicted anytime)
  • Use descriptive cache IDs
  • 使用
    get(key, loader)
    模式实现自动填充
  • 在缓存键中包含作用域(站点、目录、语言环境)
  • 为时间敏感的数据设置合适的
    expireAfterSeconds
  • 优雅处理缓存未命中的情况(数据可能随时被淘汰)
  • 使用描述性的缓存ID

Don't

不建议

  • Include personal user data in cache keys (keys may appear in logs)
  • Store Script API objects (only primitives and plain objects)
  • Rely on cache entries existing (no persistence guarantee)
  • Expect cross-server cache synchronization
  • Store
    undefined
    values (use
    null
    instead)
  • 在缓存键中包含用户个人数据(键可能出现在日志中)
  • 存储Script API对象(仅使用基本类型和普通对象)
  • 依赖缓存条目始终存在(无持久化保证)
  • 期望跨服务器缓存同步
  • 存储
    undefined
    值(使用
    null
    替代)

Cache Invalidation

缓存失效

Caches are automatically cleared when:
  • Any file in the active code version changes
  • A new code version is activated
  • Data replication completes
  • Code replication completes
Manual invalidation only affects the current application server:
javascript
var cache = CacheMgr.getCache('MyCache');

// Invalidate single entry (current app server only)
cache.invalidate('myKey');

// Storing undefined has same effect as invalidate
cache.put('myKey', undefined);
在以下情况时缓存会自动清除:
  • 活动代码版本中的任何文件发生变更
  • 激活新的代码版本
  • 数据复制完成
  • 代码复制完成
手动失效仅影响当前应用服务器:
javascript
var cache = CacheMgr.getCache('MyCache');

// 失效单个条目(仅当前应用服务器)
cache.invalidate('myKey');

// 存储undefined与执行invalidate效果相同
cache.put('myKey', undefined);

Common Patterns

常见模式

Caching External API Responses

缓存外部API响应

javascript
var CacheMgr = require('dw/system/CacheMgr');
var LocalServiceRegistry = require('dw/svc/LocalServiceRegistry');

var priceCache = CacheMgr.getCache('ExternalPriceCache');

function getExternalPrice(productID) {
    return priceCache.get('price_' + productID, function() {
        var service = LocalServiceRegistry.createService('PriceService', {
            createRequest: function(svc, args) {
                svc.setRequestMethod('GET');
                svc.addParam('productId', args.productID);
                return null;
            },
            parseResponse: function(svc, response) {
                return JSON.parse(response.text);
            }
        });

        var result = service.call({ productID: productID });
        return result.ok ? result.object : null;
    });
}
javascript
var CacheMgr = require('dw/system/CacheMgr');
var LocalServiceRegistry = require('dw/svc/LocalServiceRegistry');

var priceCache = CacheMgr.getCache('ExternalPriceCache');

function getExternalPrice(productID) {
    return priceCache.get('price_' + productID, function() {
        var service = LocalServiceRegistry.createService('PriceService', {
            createRequest: function(svc, args) {
                svc.setRequestMethod('GET');
                svc.addParam('productId', args.productID);
                return null;
            },
            parseResponse: function(svc, response) {
                return JSON.parse(response.text);
            }
        });

        var result = service.call({ productID: productID });
        return result.ok ? result.object : null;
    });
}

Caching Expensive Calculations

缓存高成本计算结果

javascript
var CacheMgr = require('dw/system/CacheMgr');

var saleCache = CacheMgr.getCache('ProductSaleCache');

function isProductOnSale(masterProduct) {
    return saleCache.get('sale_' + masterProduct.ID, function() {
        var variants = masterProduct.variants.iterator();
        while (variants.hasNext()) {
            var variant = variants.next();
            if (isInPromotion(variant)) {
                return true;
            }
        }
        return false;
    });
}
javascript
var CacheMgr = require('dw/system/CacheMgr');

var saleCache = CacheMgr.getCache('ProductSaleCache');

function isProductOnSale(masterProduct) {
    return saleCache.get('sale_' + masterProduct.ID, function() {
        var variants = masterProduct.variants.iterator();
        while (variants.hasNext()) {
            var variant = variants.next();
            if (isInPromotion(variant)) {
                return true;
            }
        }
        return false;
    });
}

Configuration Cache with Site Scope

带站点作用域的配置缓存

javascript
var CacheMgr = require('dw/system/CacheMgr');
var Site = require('dw/system/Site');
var File = require('dw/io/File');
var FileReader = require('dw/io/FileReader');

var configCache = CacheMgr.getCache('SiteConfigCache');

function getSiteConfig() {
    var siteID = Site.current.ID;

    return configCache.get(siteID + '_config', function() {
        var configFile = new File(File.IMPEX + '/src/config/' + siteID + '.json');
        if (!configFile.exists()) {
            return null;
        }

        var reader = new FileReader(configFile);
        var content = reader.getString();
        reader.close();

        return JSON.parse(content);
    });
}
javascript
var CacheMgr = require('dw/system/CacheMgr');
var Site = require('dw/system/Site');
var File = require('dw/io/File');
var FileReader = require('dw/io/FileReader');

var configCache = CacheMgr.getCache('SiteConfigCache');

function getSiteConfig() {
    var siteID = Site.current.ID;

    return configCache.get(siteID + '_config', function() {
        var configFile = new File(File.IMPEX + '/src/config/' + siteID + '.json');
        if (!configFile.exists()) {
            return null;
        }

        var reader = new FileReader(configFile);
        var content = reader.getString();
        reader.close();

        return JSON.parse(content);
    });
}

Troubleshooting

故障排查

IssueCauseSolution
Cache not found exceptionCache ID not defined in any caches.jsonAdd cache definition to caches.json
Duplicate cache ID errorSame ID used in multiple cartridgesUse unique IDs across all cartridges
Entry not storedValue exceeds 128 KB limitReduce data size or cache subsets
Entry not storedValue contains Script API objectsUse only primitives and plain objects
Unexpected cache missesDifferent app server or cache clearedAlways handle misses gracefully
Check the custom error log and custom warn log for cache-related messages.
问题原因解决方案
缓存未找到异常缓存ID未在任何caches.json中定义在caches.json中添加缓存定义
重复缓存ID错误多个cartridge使用了相同的ID在所有cartridge中使用唯一的ID
条目未存储值超过128 KB限制减小数据大小或缓存子集数据
条目未存储值包含Script API对象仅使用基本类型和普通对象
意外的缓存未命中应用服务器不同或缓存已被清除始终优雅处理未命中情况
查看自定义错误日志和自定义警告日志获取缓存相关信息。