mcpField
B
b2c-custom-job-steps

b2c-custom-job-steps

github.com/salesforcecommercecloud開発5783 回インストール今日更新
リポジトリ

b2c-custom-job-steps について

Salesforce B2C Commerceの開発者向けに、カスタムバッチジョブステップの作成方法を案内するスキルです。タスク型とチャンク型の実行、ステップ定義、ジョブ設定、標準ステップとの連携を扱います。

主な機能

  1. 01タスク型・チャンク型ステップの設計
  2. 02steptypes.json と jobs.xml の設定
  3. 03ステップパラメーターの定義と検証
  4. 04カスタムステップと標準ステップの連結
  5. 05IMPEX を介したファイル連携

活用シーン

  1. 01商品や注文のインポートジョブ作成
  2. 02データエクスポートやシステム間同期
  3. 03クリーンアップ・保守タスクの実装

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/salesforcecommercecloud/b2c-developer-tooling --skill b2c-custom-job-steps

インストール後、Claude Code で/b2c-custom-job-stepsを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

evals/
trigger-evals.json
references/
CHUNK-ORIENTED.md
JOBS-XML.md
STEPTYPES-JSON.md
TASK-ORIENTED.md

詳細

カスタムジョブステップスキル

このスキルでは、Salesforce B2C Commerce のバッチ処理向けに新しいカスタムジョブステップを作成する方法を説明します。

既存のジョブを実行しますか? CLI 経由でジョブを実行したり、サイトアーカイブをインポートしたりする場合は、代わりに b2c-cli:b2c-job スキルを使用してください。

使用する場面

  • バッチ処理向けの新しいスケジュール済みジョブを作成する
  • データインポートジョブ(顧客、商品、注文)を構築する
  • データエクスポートジョブ(レポート、フィード、同期)を構築する
  • システム間のデータ同期を実装する
  • クリーンアップまたはメンテナンスタスクを作成する

概要

カスタムジョブステップを使うと、B2C Commerce のジョブの一部としてカスタムビジネスロジックを実行できます。実行モデルは 2 種類あります。

モデル使用例進捗状況の追跡
タスク指向単一の操作(FTP、インポート/エクスポート)限定的
チャンク指向大量データの処理詳細

ファイル構成

my_cartridge/
├── cartridge/
│   ├── scripts/
│   │   └── steps/
│   │       ├── myTaskStep.js       # Task-oriented script
│   │       └── myChunkStep.js      # Chunk-oriented script
│   └── my_cartridge.properties
└── steptypes.json                  # Step type definitions (at cartridge ROOT)

重要: steptypes.json ファイルは、cartridge/ ディレクトリ内ではなく、カートリッジのルートフォルダーに配置する必要があります。1 つのカートリッジにつき、steptypes.json ファイルは 1 つだけです。

ステップタイプの定義(steptypes.json)

{
    "step-types": {
        "script-module-step": [
            {
                "@type-id": "custom.MyTaskStep",
                "@supports-parallel-execution": "false",
                "@supports-site-context": "true",
                "@supports-organization-context": "false",
                "description": "My custom task step",
                "module": "my_cartridge/cartridge/scripts/steps/myTaskStep.js",
                "function": "execute",
                "timeout-in-seconds": 900,
                "parameters": {
                    "parameter": [
                        {
                            "@name": "InputFile",
                            "@type": "string",
                            "@required": "true",
                            "description": "Path to input file"
                        },
                        {
                            "@name": "Enabled",
                            "@type": "boolean",
                            "@required": "false",
                            "default-value": "true",
                            "description": "Enable processing"
                        }
                    ]
                },
                "status-codes": {
                    "status": [
                        {
                            "@code": "OK",
                            "description": "Step completed successfully"
                        },
                        {
                            "@code": "ERROR",
                            "description": "Step failed"
                        },
                        {
                            "@code": "NO_DATA",
                            "description": "No data to process"
                        }
                    ]
                }
            }
        ],
        "chunk-script-module-step": [
            {
                "@type-id": "custom.MyChunkStep",
                "@supports-parallel-execution": "true",
                "@supports-site-context": "true",
                "@supports-organization-context": "false",
                "description": "Bulk data processing step",
                "module": "my_cartridge/cartridge/scripts/steps/myChunkStep.js",
                "before-step-function": "beforeStep",
                "read-function": "read",
                "process-function": "process",
                "write-function": "write",
                "after-step-function": "afterStep",
                "total-count-function": "getTotalCount",
                "chunk-size": 100,
                "transactional": "false",
                "timeout-in-seconds": 1800,
                "parameters": {
                    "parameter": [
                        {
                            "@name": "CategoryId",
                            "@type": "string",
                            "@required": "true"
                        }
                    ]
                }
            }
        ]
    }
}

ステップタイプから実行可能なジョブへ(jobs.xml)

steptypes.json はステップタイプを宣言するだけで、ジョブは作成しません。b2c job run で実行でき、Business Manager でスケジュールできるジョブを作成するには、ステップタイプを参照するジョブ定義(jobs.xml)を記述してからインポートします。

b2c job import ./my-job-archive   # jobs.xml at the archive root

有効な最小限の定義では、1 つのステップをフローに接続し、必須の <triggers> 要素を含めます。

<?xml version="1.0" encoding="UTF-8"?>
<jobs xmlns="http://www.demandware.com/xml/impex/jobs/2015-07-01">
    <job job-id="MyNightlyExport">
        <flow>
            <context site-id="RefArch"/>
            
            <step step-id="ExportStep" type="custom.ProductExport">
                <parameters>
                    <parameter name="OutputFile">/export/products.csv</parameter>
                </parameters>
            </step>
        </flow>
        <triggers>
            <run-once enabled="false">
                <date>2025-01-01</date>
                <time>00:00:00.000Z</time>
            </run-once>
        </triggers>
    </job>
</jobs>

主なルール(詳細は jobs.xml リファレンスを参照してください):

  • <triggers> はスキーマで必須です。これがない jobs.xml はインポート検証に失敗します。オンデマンドまたは手動実行のジョブには <run-once enabled="false"> を、スケジュールする場合は <run-recurring> を使用します。
  • <step> の type 属性はステップタイプを参照します。その値は、steptypes.json で宣言した @type-id と一致する必要があります(混同しないでください。steptypes.json では @type-id、jobs.xml では type を使用します)。
  • <job> の子要素は、次の順序で記述する必要があります:description → parameters → flow/split → rules → triggers。
  • ジョブがステップタイプを解決できるようにするには、ステップの steptypes.json とモジュールを含むカートリッジをデプロイし、カートリッジパスに追加しておく必要があります。

インポート後、b2c job run MyNightlyExport --wait で実行します(b2c-cli:b2c-job スキルを参照してください)。

タスク指向のステップ

FTP 転送、ファイル生成、インポート/エクスポートなどの単一操作に使用します。

スクリプト(scripts/steps/myTaskStep.js)
'use strict';

var Status = require('dw/system/Status');
var Logger = require('dw/system/Logger');

/**
 * Execute the task step
 * @param {Object} parameters - Job step parameters
 * @param {dw.job.JobStepExecution} stepExecution - Step execution context
 * @returns {dw.system.Status} Execution status
 */
exports.execute = function (parameters, stepExecution) {
    var log = Logger.getLogger('job', 'MyTaskStep');

    try {
        var inputFile = parameters.InputFile;
        var enabled = parameters.Enabled;

        if (!enabled) {
            log.info('Step disabled, skipping');
            return new Status(Status.OK, 'SKIP', 'Step disabled');
        }

        // Your business logic here
        log.info('Processing file: ' + inputFile);

        // Return success
        return new Status(Status.OK);

    } catch (e) {
        log.error('Step failed: ' + e.message);
        return new Status(Status.ERROR, 'ERROR', e.message);
    }
};
ステータスコード
// Success
return new Status(Status.OK);
return new Status(Status.OK, 'CUSTOM_CODE', 'Custom message');

// Error
return new Status(Status.ERROR);
return new Status(Status.ERROR, null, 'Error message');

重要: カスタムステータスコードは、ステータスが OK の場合にのみ機能します。ERROR ステータスでカスタムコードを使用すると、ERROR に置き換えられます。カスタムステータスコードには、カンマ、ワイルドカード、先頭または末尾の空白を含めることはできません。また、100 文字を超えることもできません。

チャンク指向のステップ

数えられるデータ(商品、注文、顧客)の一括処理に使用します。

重要: チャンク指向のステップでは、カスタム終了ステータスを定義できません。チャンクモジュールは、常に OK または ERROR のいずれかで終了します。

必須関数
関数目的戻り値
read()次の項目を取得する項目、または何も返さない
process(item)項目を変換する処理済みの項目、または何も返さない(フィルター)
write(items)項目のチャンクを保存する何も返さない
任意の関数
関数目的戻り値
beforeStep()初期化する(ファイル、クエリを開く)何も返さない
afterStep(success)クリーンアップする(ファイルを閉じる)何も返さない
getTotalCount()進捗表示用に総項目数を返す数値
beforeChunk()各チャンクの前に実行する何も返さない
afterChunk()各チャンクの後に実行する何も返さない
スクリプト(scripts/steps/myChunkStep.js)
'use strict';

var ProductMgr = require('dw/catalog/ProductMgr');
var Transaction = require('dw/system/Transaction');
var Logger = require('dw/system/Logger');
var File = require('dw/io/File');
var FileWriter = require('dw/io/FileWriter');

var log = Logger.getLogger('job', 'MyChunkStep');
var products;
var fileWriter;

/**
 * Initialize before processing
 */
exports.beforeStep = function (parameters, stepExecution) {
    log.info('Starting chunk processing');

    // Open resources
    var outputFile = new File(File.IMPEX + '/export/products.csv');
    fileWriter = new FileWriter(outputFile);
    fileWriter.writeLine('ID,Name,Price');

    // Query products
    products = ProductMgr.queryAllSiteProducts();
};

/**
 * Get total count for progress tracking
 */
exports.getTotalCount = function (parameters, stepExecution) {
    return products.count;
};

/**
 * Read next item
 * Return nothing to signal end of data
 */
exports.read = function (parameters, stepExecution) {
    if (products.hasNext()) {
        return products.next();
    }
    // Return nothing = end of data
};

/**
 * Process single item
 * Return nothing to filter out item
 */
exports.process = function (product, parameters, stepExecution) {
    // Filter: skip offline products
    if (!product.online) {
        return;  // Filtered out
    }

    // Transform
    return {
        id: product.ID,
        name: product.name,
        price: product.priceModel.price.value
    };
};

/**
 * Write chunk of processed items
 */
exports.write = function (items, parameters, stepExecution) {
    for (var i = 0; i < items.size(); i++) {
        var item = items.get(i);
        fileWriter.writeLine(item.id + ',' + item.name + ',' + item.price);
    }
};

/**
 * Cleanup after all chunks
 */
exports.afterStep = function (success, parameters, stepExecution) {
    // Close resources
    if (fileWriter) {
        fileWriter.close();
    }
    if (products) {
        products.close();
    }

    if (success) {
        log.info('Chunk processing completed successfully');
    } else {
        log.error('Chunk processing failed');
    }
};

パラメーターの型

型説明値の例
stringテキスト値"my-value"
booleantrue/falsetrue
long整数12345
double小数123.45
datetime-stringISO 日時"2024-01-15T10:30:00Z"
date-stringISO 日付"2024-01-15"
time-stringISO 時刻"10:30:00"
パラメーターの検証属性
属性適用対象説明
@trimすべて検証前に空白を削除します(デフォルト:true)
@requiredすべて必須として設定します(デフォルト:true)
@target-typedatetime-string, date-string, time-stringlong または date に変換します(デフォルト:date)
patternstring検証用の正規表現パターン
min-lengthstring文字列の最小長(1 以上)
max-lengthstring文字列の最大長(合計最大 1000 文字)
min-valuelong, double, datetime-string, time-string数値の最小値
max-valuelong, double, datetime-string, time-string数値の最大値
enum-valuesすべて使用可能な値に制限します(BM のドロップダウン)

設定オプション

steptypes.json の属性
属性必須説明
@type-idはい一意の ID(custom. で始まる必要があり、最大 100 文字)
@supports-parallel-executionいいえ並列実行を許可します(デフォルト:true)
@supports-site-contextいいえサイトスコープのジョブで使用可能です(デフォルト:true)
@supports-organization-contextいいえ組織スコープのジョブで使用可能です(デフォルト:true)
moduleはいスクリプトモジュールへのパス
functionはい実行する関数名(タスク指向)
timeout-in-secondsいいえステップのタイムアウト(設定を推奨)
transactionalいいえ単一のトランザクションでラップします(デフォルト:false)
chunk-sizeはい*チャンクあたりの項目数(*チャンクステップで必須)

コンテキストの制約: @supports-site-context と @supports-organization-context の両方を true または両方を false にすることはできません。一方を true、もう一方を false にする必要があります。

標準(システム)ジョブステップ

カスタムステップはジョブフローの一部にすぎません。B2C Commerce には、標準(システム)ジョブステップも用意されています。これらは組み込みのステップ タイプ ID で、Business Manager → Administration → Operations → Jobs からフローに追加するか、サイトインポートアーカイブ内の jobs.xml フローでタイプ ID を指定して参照します。カスタムステップとは異なり、これらを steptypes.json で宣言する必要はありません。常に使用できます。カタログ/在庫/価格/コンテンツ/クーポン/カスタムオブジェクトのインポートとエクスポート、注文のエクスポート、および同様のプラットフォーム操作に使用し、カスタムステップと連結してください。

標準ステップのタイプ ID やパラメーターを推測しないでください。 各ステップの目的と設定パラメーター(必須項目、デフォルト値、使用可能な値)を網羅した完全なカタログが CLI に同梱されており、b2c-cli:b2c-docs スキルから検索できます。

# Browse the catalog of standard step type IDs
b2c docs read job-steps

# Look up a specific step's purpose + configuration parameters
b2c docs read ImportCatalog
b2c docs read ExportInventoryLists

# Fuzzy-search for a step
b2c docs search "import price"
一般的に使用される標準ステップ

同梱されているカタログには、Business Manager のジョブステップ選択画面に表示される標準ステップタイプ ID 一式(インポート、エクスポート、処理ステップ)が含まれています。以下は代表的な一部です。完全なリストは b2c docs read job-steps を実行して確認できます。また、各ステップの全パラメーターとデフォルト値は b2c docs read <TypeID> で確認できます。スコープは実行スコープ(Organization、Site、または両方)です。

Type IDスコープ主な必須パラメーター
ImportCatalogOrganizationNoFilesFoundHandling、ImportMode、ImportFailedHandling
ImportInventoryListsOrganizationNoFilesFoundHandling、ImportMode、ImportFailedHandling
ImportPriceBookOrganizationNoFilesFoundHandling、ImportMode、ImportFailedHandling
ImportContentSiteNoFilesFoundHandling、ImportMode、ImportFailedHandling
ImportCustomObjectsOrganization と SitesNoFilesFoundHandling、ImportFailedHandling
ExportCatalogOrganizationCatalogID
ExportInventoryListsSiteなし
ExportPriceBookOrganizationPriceBookID
ExportContentOrganization と SitesLibraryID
ExportOrdersSiteConfirmation Status、Shipment Status、Payment Status
ExecutePreconfiguredDataReplicationProcessOrganizationReplicationProcessID
SearchReindexSiteIndexer Type
ExecuteScriptModuleOrganization と SitesExecuteScriptModule.Module

インポートステップでは、共通のファイル処理パラメーター(WorkingFolder、FileNamePattern、ImportMode、NoFilesFoundHandling、ImportFailedHandling、AfterImportFileHandling、ArchiveFolder)を使用します。エクスポートステップでは、ExportFile、FileNamePrefix、OverwriteExportFile を共通して使用します。処理ステップ(レプリケーション、再インデックス、キャッシュ無効化、ExecutePipeline/ExecuteScriptModule/IncludeStepsFromJob)には、それぞれ固有のパラメーターがあります。正確な一覧については、各ステップのドキュメントを参照してください。

前のステップで IMPEX にステージングされたファイルを参照する

標準のインポートステップは、インスタンスの IMPEX 領域から読み込みます。WorkingFolder パラメーターは IMPEX/src/ を基準に解決され(デフォルトは IMPEX/src/)、FileNamePattern はそのフォルダーからインポートするファイルを選択する正規表現です。これが引き渡しの仕組みです。IMPEX/src/... の下にファイルを書き込むステップの後に、そのファイルを読み込む標準インポートステップを続けることができます。ダウンロードとアップロードを繰り返す必要はありません。

カスタムステップでは、IMPEX 定数を使って dw.io.File でその場所に書き込みます。

var File = require('dw/io/File');

// Custom step writes a catalog import file into IMPEX/src/jobdata/
exports.beforeStep = function () {
    var dir = new File(File.IMPEX + '/src/jobdata');
    dir.mkdirs();
    outputFile = new File(dir, 'catalog-' + Date.now() + '.xml');
    fileWriter = new dw.io.FileWriter(outputFile);
    // ... write valid catalog XML (validate against the `catalog` XSD:
    //     b2c docs schema catalog) ...
};

次にフローのステージにある標準の ImportCatalog ステップで、WorkingFolder を src/jobdata(IMPEX/src/ からの相対パスなので jobdata を指定)に設定し、FileNamePattern に catalog-.*\.xml を指定してファイルを読み込みます。

1 つのフローでカスタムステップと標準ステップを連結する

フローでは、カスタムステップと標準ステップを交互に配置できます。例:カスタムステップで外部システムからデータを取得し、IMPEX にカタログ XML を生成します。次に標準の ImportCatalog ステップでそれを適用し、最後に標準のレプリケーションステップで変更を本番環境に公開します。


<job job-id="NightlyCatalogSync">
  <flow>
    
    <step step-id="generateCatalog" type="custom.GenerateCatalogExport">
      <parameters>
        <parameter name="OutputFolder">jobdata</parameter>
      </parameters>
    </step>

    
    <step step-id="importCatalog" type="ImportCatalog">
      <parameters>
        <parameter name="WorkingFolder">jobdata</parameter>
        <parameter name="FileNamePattern">catalog-.*\.xml</parameter>
        <parameter name="ImportMode">Merge</parameter>
        <parameter name="NoFilesFoundHandling">ERROR</parameter>
        <parameter name="ImportFailedHandling">ERROR</parameter>
        <parameter name="AfterImportFileHandling">Archive</parameter>
      </parameters>
    </step>

    
    <step step-id="publishCatalog" type="ExecutePreconfiguredDataReplicationProcess">
      <parameters>
        <parameter name="ReplicationProcessID">nightly-catalog-publish</parameter>
      </parameters>
    </step>
  </flow>
</job>

カスタムステップの OutputFolder と標準ステップの WorkingFolder はどちらも jobdata(つまり IMPEX/src/jobdata/)を指定するため、ステップ 1 で書き込んだファイルをステップ 2 がそのままインポートし、ステップ 3 で結果をレプリケートします。(Business Manager では、同じフローを画面上で構築できます。カスタムステップを追加し、その後に標準の ImportCatalog ステップ、続けてレプリケーションステップを追加して、それぞれのフォームで各ステップのパラメーターを設定します。)

フロー内の標準ステップと CLI の同等機能

一部の標準ステップは b2c CLI コマンドと機能が重複します(CLI の b2c job import/b2c job export は、sfcc-site-archive-import/-export システムジョブそのものです)。データの保存場所に応じて選択してください。

  • ファイルがインスタンス上で生成される、またはすでにステージングされている場合は、フロー内の標準ステップを使用します。特に、同じフロー内の前のステップでファイルが生成された場合(往復が不要)、Business Manager のスケジュールに従って実行する場合、またはサーバー側でカスタム処理を行う必要がある場合に適しています。例:前のカスタムステップが IMPEX に書き込んだカタログ XML を処理する標準の ImportCatalog ステップ。
  • データをマシンとインスタンスの間で移動する場合は、CLI(b2c job import、b2c job export)を使用します。ローカルのアーカイブをアップロードする場合、エクスポートをダウンロードする場合、または CI から単発の処理をスクリプトで実行する場合などです。

判断の目安:インスタンス上にすでにある(またはインスタンス上で生成された)データ → フロー内の標準ステップ、マシンとインスタンスの境界を越えて移動するデータ → CLI。CLI については b2c-cli:b2c-job スキルを参照してください。

ベストプラクティス

  1. 大量データにはチャンク指向を使用します。進行状況の追跡と再開が容易になります
  2. afterStep() でリソースを閉じます。クエリ、ファイル、接続などが対象です
  3. タイムアウトを明示的に設定します。デフォルトでは短すぎる場合があります
  4. 進行状況をログに記録します。デバッグに役立ちます
  5. エラーを適切に処理します。適切な Status オブジェクトを返します
  6. transactional=true に依存しないでください。制御には Transaction.wrap() を使用します

関連スキル

  • b2c-cli:b2c-job - 既存のジョブの実行と、CLI によるサイトアーカイブのインポートについて
  • b2c-cli:b2c-docs - 標準ジョブステップのタイプ ID とパラメーターを確認する場合(b2c docs read job-steps、b2c docs read <TypeID>)
  • b2c:b2c-webservices - ジョブステップから外部 HTTP サービスや API を呼び出す場合。サービス設定と HTTP クライアントのパターンについては、webservices スキルを使用してください

詳細リファレンス

コメント