b2c-custom-caches について
b2c-custom-caches は、Salesforce B2C Commerce でアプリケーションレベルのキャッシュを実装する開発者向けのスキルです。JSON 定義と Script API の使い方に加え、ローダーによる登録、キーのスコープ、有効期限、制限を説明します。
主な機能
- 01JSON ファイルでのキャッシュ定義
- 02Script API によるキャッシュ利用
- 03ローダー関数でのエントリ登録
- 04サイトやカタログ単位のキー設定
- 05有効期限と無効化の設定
活用シーン
- 01外部 API レスポンスのキャッシュ
- 02高コストな計算の重複回避
- 03頻繁に使う商品データの再利用
- 04サイト別設定のキャッシュ
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ salesforcecommercecloud/ b2c-developer-tooling --skill b2c-custom-cachesインストール後、Claude Code で/b2c-custom-cachesを入力して読み込まれたか確認します。
同梱ファイルevals/trigger-evals.json
詳細
B2C カスタムキャッシュ
カスタムキャッシュは、計算コストが高いデータ、取得に時間がかかるデータ、または頻繁にアクセスされるデータを保存することで、コードのパフォーマンスを向上させます。キャッシュはカートリッジ内の JSON ファイルで定義し、Script API 経由でアクセスします。
カスタムキャッシュを使用する場面
| ユースケース | 例 |
|---|---|
| 計算コストの高い処理 | ベース商品の表示にあたり、バリエーション商品のいずれかがセール中かどうかを確認する |
| 外部システムからの応答 | 外部 API から取得した店舗在庫や価格をキャッシュする |
| 設定 | JSON ファイルまたは外部ソースから取得した設定データを保存する |
| 頻繁にアクセスされるデータ | 商品属性、カテゴリーのデータ、サイトの環境設定 |
制限事項
| 制約 | 値 |
|---|---|
| アプリケーションサーバーごとの合計メモリ | すべてのカスタムキャッシュで約 20 MB |
| コードバージョンごとの最大キャッシュ数 | 100 |
| エントリーの最大サイズ | 128 KB |
| サポートされる値の型 | プリミティブ、配列、プレーンオブジェクト、null(undefined は不可) |
| サーバー間の同期 | なし(キャッシュはアプリケーションサーバーごと) |
カスタムキャッシュの定義
ファイル構成
my_cartridge/
├── package.json # References caches.json
└── caches.json # Cache definitions
package.json
キャッシュ定義ファイルを指定する caches エントリーを追加します。
{
"name": "my_cartridge",
"caches": "./caches.json"
}
caches.json
一意の ID と任意の有効期限を指定してキャッシュを定義します。
{
"caches": [
{
"id": "ProductAttributeCache"
},
{
"id": "ExternalPriceCache",
"expireAfterSeconds": 300
},
{
"id": "SiteConfigCache",
"expireAfterSeconds": 60
}
]
}
| プロパティ | 必須 | 説明 |
|---|---|---|
id | はい | コードバージョン内のすべてのカートリッジで一意の ID |
expireAfterSeconds | いいえ | エントリーを保持する最大秒数 |
カスタムキャッシュの使用
Script API クラス
| クラス | 説明 |
|---|---|
dw.system.CacheMgr | 定義済みキャッシュにアクセスするためのエントリーポイント |
dw.system.Cache | エントリーの保存と取得に使用するキャッシュインスタンス |
基本的な使い方
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');
推奨パターン:ローダーを使った get
get(key, loader) を使うと、キャッシュミス時にキャッシュへ自動的に値を登録できます。
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);
});
スコープ付きキャッシュキー
キーにスコープ識別子を含め、コンテキストごとにエントリーを分けます。
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);
キャッシュメソッド
| メソッド | 説明 |
|---|---|
get(key) | キャッシュされた値、または undefined を返します |
get(key, loader) | キャッシュされた値を返すか、ローダーを呼び出して結果を保存します |
put(key, value) | 値を直接保存します(既存の値は上書きされます) |
invalidate(key) | キーに対応するエントリーを削除します |
ベストプラクティス
推奨事項
- 自動登録には
get(key, loader)パターンを使用します - キャッシュキーにスコープ(サイト、カタログ、ロケール)を含めます
- 時間の経過で変化するデータには適切な
expireAfterSecondsを設定します - キャッシュミスを適切に処理します(データはいつでも削除される可能性があります)
- わかりやすいキャッシュ ID を使用します
避けるべき事項
- 個人ユーザーデータをキャッシュキーに含めないでください(キーがログに記録される可能性があります)
- Script API オブジェクトを保存しないでください(プリミティブとプレーンオブジェクトのみ使用してください)
- キャッシュエントリーが存在することを前提にしないでください(永続性は保証されません)
- サーバー間でキャッシュが同期されることを期待しないでください
undefinedの値を保存しないでください(代わりにnullを使用します)
キャッシュの無効化
キャッシュは次の場合に自動的にクリアされます。
- アクティブなコードバージョン内のファイルが変更された場合
- 新しいコードバージョンが有効化された場合
- データレプリケーションが完了した場合
- コードレプリケーションが完了した場合
手動での無効化は、現在のアプリケーションサーバーにのみ適用されます。
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);
よくあるパターン
外部 API 応答のキャッシュ
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;
});
}
計算コストの高い処理のキャッシュ
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;
});
}
サイトスコープを指定した設定キャッシュ
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);
});
}
トラブルシューティング
| 問題 | 原因 | 解決方法 |
|---|---|---|
| キャッシュが見つからない例外 | どの caches.json にもキャッシュ ID が定義されていない | caches.json にキャッシュ定義を追加します |
| キャッシュ ID の重複エラー | 複数のカートリッジで同じ ID が使用されている | すべてのカートリッジで一意の ID を使用します |
| エントリーが保存されない | 値が 128 KB の上限を超えている | データサイズを小さくするか、データの一部だけをキャッシュします |
| エントリーが保存されない | 値に Script API オブジェクトが含まれている | プリミティブとプレーンオブジェクトのみ使用します |
| キャッシュミスが予期せず発生する | 別のアプリケーションサーバーを使用しているか、キャッシュがクリアされた | 常にキャッシュミスを適切に処理します |
キャッシュ関連のメッセージについては、カスタムエラーログとカスタム警告ログを確認してください。
コメント
Markdown 対応