2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Salesforce B2C Commerce の SFRA にてジョブを利用して SFTP で AWS S3 にファイルアップロードしてみる

Last updated at Posted at 2022-07-13

※ これから記載する事項は、私が所属する会社とは一切関係のない事柄です。

本記事では B2C Commerce のジョブと AWS の Transfer Family を利用して AWS S3 にファイルをアップロードしたいと思います

ジョブの概要

まず少し、ジョブについて説明します。ジョブを作成するときはジョブステップを組み合わせながらフローを作成していきます。
スクリーンショット 2022-07-12 18.23.08.png

上記の画像 A、B、C のジョブステップで構成されたフローを「(並列、順次)同位フロー」と呼びます。デフォルトではそれぞで同時に(並列に)実行されますが、左から順次実行するように設定することも可能です。並列実行するリソースがなかったり、並列実行できないステップが混ざっていると、順次実行されます。

Aの中にも複数のステップを設定できますが、これらは順次実行されます。

画像の上から下への矢印のように同位フローが実行が終了されたら一つ下の同位フローへと順次実行されます。これを「順次フロー」

デフォルトでは下記のようになります。

A、B、C が同時に実行される。

D、F が同時に実行される

F が実行される

その他できること

下記のように他にもできることは多くありますが、それらについては TrailheadInfocenter をご覧ください。

  • ジョブ実行中にオブジェクトをロックして、他のユーザからの修正や他のジョブから修正されないようにできます
  • スケジュールでの実行ができます
  • ジョブパラメータを利用して複数のジョブステップで共通のパラメータを利用することができます
  • あらかじめ作成されてすぐ利用できるシステムジョブステップがあります
  • 自作のカスタムジョブステップを作成できます
  • ジョブ実行結果の通知

実装内容

Job を利用して注文情報と顧客情報の XML ファイルを Transfer Famify を通して SFTP で S3 にアップロードします。
※リソースのロックやスケジュール実行、通知については取り扱いません。
※カスタムジョブステップは Chunk-Oriented Script ModuleTask-Oriented Script Module がありますが、今回作成するのは Task-Oriented Script Module のみです。

スクリーンショット 2022-07-12 18.42.05.png

仕様

  • 「ExportCustomers」システムジョブステップで顧客情報を B2C Commerce のストレージ内の /Impex/src/sample/customers/20220711.xmlに出力
  • 「Custom.SampleUploadModule」というカスタムジョブを作成し、/Impex/src/sample/customers/20220711.xml に出力されたファイルを SFTP で S3 バケット「cc-sd-job-test」 内の Import/RefArch/customers/20220711.xmlにアップロード
  • 「ExportOrders」システムジョブステップで注文情報を B2C Commerce のストレージ内の /Impex/src/sample/orders/20220711.xmlに出力
  • 「Custom.SampleUploadModule」というカスタムジョブを作成し、/Impex/src/sample/orders/20220711.xml に出力されたファイルをSFTPでS3バケット「cc-sd-job-test」 内の Import/RefArch/orders/20220711.xmlにアップロード

実装手順

1. AWS Transfer FamilyとS3の設定

公式ドキュメントがあるので、こちらをステップ2まで実行してください。

2. SFTP認証のための秘密鍵と公開鍵の作成

下記のコマンドをローカルで上から順番に実行してください。
すると 「key」「key.p12」「cert.cer」「key.pub」をいう4つのファイルがカレントディレクトリに生成されます。
この際に設定したパスワードは後ほど使うので覚えておいてください

ssh-keygen -t rsa -b 2048 -m PEM -f key
openssl req -new -x509 -key key -out cert.cer -days 365
openssl pkcs12 -export -out key.p12 -inkey key -in cert.cer

3. 秘密鍵の保管

Business Manager の 管理 > オペレーション > 秘密鍵と証明書 に遷移し、上記で作成した「key.p12」秘密鍵ファイルをインポートします。
この際、上記で設定したパスワードを入力してください。
また、任意のエイリアスを設定できますので、その値も覚えておいてください。

image (10).png

4. AWS Transfer Familyへのユーザの設定

公式ドキュメントのステップ3を実行してください。
その際、手順8の「[SSH public key] (SSH 公開キー) に SSH キーペアの SSH 公開キー部分を入力します。」で上記で生成した「key.pub」のファイルの中身を入力してください。
また、ユーザ名も後ほど利用するのでメモしておいてください。
今回は「sample-user」というユーザ名のユーザを作成しました。

image (32).png

5. AWS Transfer Family のドメインとユーザの取得

AWS のコンソールからドメインとユーザ名をコピーしておきます。

スクリーンショット 2022-07-12 19.13.49 (1).png

6. Service の作成

サービスの作成を行います。
詳細については、下記のヘルプを参照してください。

認証情報の設定の際に上記で取得したドメインとユーザ名を入力する必要があります。
今回は「sample.job.test」というサービスを作成しました。下記に設定した内容の画像を添付します。

サービスの設定

image (12).png

プロフィールの設定

image (13).png

認証情報の設定

スクリーンショット 2022-07-12 19.12.19.png

7. S3にパスを設定しておく

今回作成した S3 バケットは「cc-sd-job-test」です。
このバケット内にあらかじめ下記のフォルダを作成しておきます。

  • Import/RefArch/customers
  • Import/RefArch/orders

image (14).png

8. カスタムジョブステップの作成

カートリッジ内にカスタムジョブステップを作成し、 B2C Commerce にアップロードし、カートリッジパスを設定します。
カスタムジョブステップの作成方法の詳しい作り方はTrailheadInfocenterをご覧ください。
※ カートリッジの作成方法やアップロード方法については割愛します。詳しくは TrailheadInfocenter以前紹介した Qiita 記事 をご参照ください

今回は「app_job_test」というカートリッジに下記の2つのファイルを作成します。

  • samplejob は秘密鍵を Business Manager に保管した際のエイリアスです。今回はコード内にベタ書きですが、これはジョブパラメータで受け取るようにしてもいいかと思います。
  • dirNamedestFilePath でパスを設定しています。要件に合わせてパスを変更したり、ファイル名を自動生成にしたり、アーカイブにファイルを移動させるなどしてください。
scripts/jobs/upload.js
"use strict";

const File = require("dw/io/File");
const LocalServiceRegistry = require("dw/svc/LocalServiceRegistry");
const Status = require("dw/system/Status");
const KeyRef = require("dw/crypto/KeyRef");

function sftpUpload(params, stepExecution) {
    var sftpService = registerSFTP(params.SFTPServiceID);
    var siteID = require("dw/system/Site").current.ID;
    var dirName = File.IMPEX + File.SEPARATOR + "src";
    var sourceFile = new File(
        dirName + File.SEPARATOR + params.SourceFilePath + ".xml"
    );
    var destFilePath =
        File.SEPARATOR +
        "cc-sd-job-test" +
        File.SEPARATOR +
        "Import" +
        File.SEPARATOR +
        siteID +
        File.SEPARATOR +
        params.DestinationFilePath +
        ".xml";

    var returnStatus;
    try {
        var uploadStatus = sftpService.call({
            sourceFile: sourceFile,
            destFilePath: destFilePath,
        });

        if (uploadStatus.ok) {
            returnStatus = new Status(Status.OK);
        } else {
            returnStatus = new Status(
                Status.ERROR,
                uploadStatus.status,
                uploadStatus.errorMessage
            );
        }
    } catch (e) {
        returnStatus = new Status(Status.ERROR, "EXCEPTION", e.toString());
    }
    return returnStatus;
}

function registerSFTP(serviceID) {
    return LocalServiceRegistry.createService(serviceID, {
        createRequest: function (svc, params) {
            svc.client.setIdentity(new KeyRef("samplejob"));
            svc.setOperation(
                "putBinary",
                params.destFilePath,
                params.sourceFile
            );
        },
        parseResponse: function (svc, uploadStatus) {
            return uploadStatus;
        },
        mockCall: function (svc, params) {},
    });
}

exports.sftpUpload = sftpUpload;
steptypes.json
{
    "step-types": {
        "script-module-step": [
            {
                "@type-id": "custom.SampleUploadModule",
                "@supports-parallel-execution": "true",
                "@supports-site-context": "true",
                "@supports-organization-context": "false",
                "description": "Upload Molule",
                "module": "app_job_test/cartridge/scripts/jobs/upload.js",
                "function": "sftpUpload",
                "transactional": "false",
                "timeout-in-seconds": "900",
                "parameters": {
                    "parameter": [
                        {
                            "@name": "SFTPServiceID",
                            "@type": "string",
                            "@required": "true",
                            "description": "SFTP Service ID",
                            "default-value": "test"
                        },
                        {
                            "@name": "DestinationFilePath",
                            "@type": "string",
                            "@required": "false",
                            "@trim": "false",
                            "description": "Target Path and Filename after /cc-sd-job-test/Import/{Site ID}/"
                        },
                        {
                            "@name": "SourceFilePath",
                            "description": "Source Path and Filename after /IMPEX/src/",
                            "@type": "string",
                            "@required": "false",
                            "@trim": "false"
                        }
                    ]
                },
                "status-codes": {
                    "status": [
                        {
                            "@code": "ERROR",
                            "description": "Used when the step failed with an error."
                        },
                        {
                            "@code": "FINISHED",
                            "description": "Used when the step finished successfully."
                        },
                        {
                            "@code": "FINISHED_WITH_WARNINGS",
                            "description": "Used when the step finished with warnings."
                        }
                    ]
                }
            }
        ]
    }
}

スクリーンショット 2022-07-13 13.02.18.png

9. ジョブの設定

今回は注文情報のエクスポートとアップロードと顧客情報のエクスポートとアップロードを並列で実行したいと思います。
今回は「test」というジョブを作成しました。
「SampleCustomerExport」と「SampleOrderExport」はそれぞれ「ExportCustomers」と「ExportOrders」というシステムジョブステップを利用しています。
システムジョブステップの利用方法は一覧をご覧ください。

image (15).png

それぞれのジョブステップの説明

共通で利用できるパラメータ
  • customerExportFilePath
    • 顧客情報を出力する先の B2C Commerce のストレージの /IMPEX/src/ 以降のパス
  • orderExportFilePath
    • 注文情報を出力する先の B2C Commerce のストレージの /IMPEX/src/ 以降のパス
  • SFTPServiceID
    • SFTP に使用するサービスの ID

image (16).png

SampleCustomerExport のポイント
  • ExportFile に customerExportFilePath パラメータを設定

image (28).png

SampleCustomerUpload のポイント
  • SFTPServiceID に SFTPServiceID パラメータを設定
  • DestinationFilePath に S3 にアップロードする際の/cc-sd-job-test/Import/{Site ID}/ 以降のパスとファイル名を指定
  • SourceFilePath には customerExportFilePath パラメータを設定

image (29).png

SampleOrderExport のポイント
  • ExportFile に orderExportFilePath パラメータを設定

image (30).png

SampleOrderUpload のポイント
  • SFTPServiceID に SFTPServiceID パラメータを設定
  • DestinationFilePath に S3 にアップロードする際の/cc-sd-job-test/Import/{Site ID}/ 以降のパスとファイル名を指定
  • SourceFilePath には orderExportFilePath パラメータを設定

image (31).png

実行してみる

今回は一回のみ手動で実行してみたいと思います。
ジョブのページの右上の「ただちに実行」をクリックすると実行されます。実行結果は「スケジュールと履歴」タブで表示されます。

スクリーンショット 2022-07-13 14.04.29.png

ステータスが OK なのを確認したらちゃんと S3 にファイルが上がっているかを確認します。

Import/RefArch/customers/20220711.xml
スクリーンショット 2022-07-13 14.06.21.png

Import/RefArch/orders/20220711.xml
スクリーンショット 2022-07-13 14.06.32.png

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?