3
2

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.

Event Meshを使わずに非同期な連携を実現する方法

Posted at

1. はじめに

この記事は SAP Advent Calendar 2022 の12月1日分の記事として執筆しています。

BTPで非同期な連携を実現する方法といえばEvent Meshが有名です。Integrasion Suiteの一部として紹介されることの多いEvent Meshですが、「サービス」としてのIntegrasion Suiteには含まれていません。
image.png
図:SAP Integration Suite – Overview, Recent Innovations, and Road Map [IN203]のセッション資料より抜粋

SAP Discovery Centerで見ると、独立したサービスとして提供されていることがわかります。
image.png
つまり、Integrasion SuiteをサブスクライブしているだけではEvent Meshは使えず、使うためには追加のお金がかかるということです。そこでこの記事では、Event Meshを使わずに非同期な連携を実現する方法を実現する方法を紹介します。

2. Event Meshを使わずに非同期な連携を実現するには

前提:Integration Suiteをサブスクライブしていること

今回はおなじみのCloud Integration (CPI)を使って非同期な連携を実装します。CPIにはJMSキューというものが用意されており、Event Meshのキューと同じようにメッセージをためることができます。下図のIntegration Flow1はJMSキューにメッセージを格納するところまでを行い、送信側にすぐ結果を返します。Integration Flow2はキューにメッセージが格納されると起動し、受信側へメッセージを送信します。これによって非同期な連携が実現できます。

キューからメッセージを取り出すJMS Sender Adapterはフローがエラーで終了した場合、成功するまで一定間隔でリトライします。これにより、受信側が一時的に利用不可であっても確実にメッセージを届けることができます。
image.png
図:Use Case for JMSより引用

3. 実装

ここではInboundとOuboundという2つのフローを実装します。Inboundは送信側からメッセージを受け取りキューに格納します。Outboundはキューからメッセージを取り出し、受信側に届けます。

3.1. 事前準備

受信側として、CAPで簡単なサービスを作成しました。

data-model.cds
namespace receiver;
using { cuid, managed } from '@sap/cds/common';

entity Messages: cuid, managed{
  message  : String;
}
receiver-service.cds
using receiver as db from '../db/data-model';

service ReceiverService {
    entity Messages as projection on db.Messages;
}

以下のようなリクエストを投げると、HANA Cloudにレコードが格納されます。

POST http://<host>/receiver/Messages
Content-Type: application/json

{
    "message": "hello"
}

3.2. Inboundのフロー

Inboundのフローでは、受け取ったメッセージをキューに格納し、送信側にレスポンスを返します。
image.png

3.2.1. フローの設定

①HTTPS Sender Adapter

Addressに任意のパスを指定します。呼び出しを簡単にするため、CSRF Protectedのチェックは外しておきます。
image.png

②JMSキューにメッセージを格納 [JMS Receiver Adapter]

Queue Nameに任意の名前を設定し、他はデフォルトのままとします。
image.png

なお、JMSキューにメッセージを格納するための"Store Message"にはSendというコンポーネントを使っています。HTTPSアダプターなどを使う場合はRequest Replyを使いますが、JMSキューへの格納はリプライを返さないためSendを使います。

③レスポンスの設定 [Content Modifier]

送信側に結果を返すため、ヘッダとボディを設定します。ボディを空で返すのでヘッダにステータスコード204 (No Content)を設定します。CPIでステータスコードを設定するには、"CamelHttpResponseCode"を使用します。
image.png
ボディはTypeを"Constant"とし、中身は空にします。
image.png

3.2.2. デプロイ

デプロイするとキューが登録されます。
image.png
この時点ではキューは空です。
image.png

3.2.3. テスト

Postmanからリクエストを送信します。
image.png
image.png
ステータス204 (No Content)で返ってきます。
image.png
キューにメッセージが格納されています。まだ受信側のキューがないので処理されずに溜まっています。
image.png

3.3. Outboundのフロー

Outboundのフローでは、キューからメッセージを取り出し、事前準備で作成したODataサービスに送信します。
image.png

3.3.1. フローの設定

①キューからメッセージを取得 [JMS Sender Adapter]

Inboundのフローで指定したのと同じキュー名を指定します。
image.png

②ヘッダの設定 [Content Modifier]

ヘッダにContent-Type (application/json)を設定します。
image.png

③受信側にメッセージを送信 [HTTPS Receiver Adapter]

受信側のODataサービスにメッセージを送信します。OData V4 AdapterではXML形式のメッセージしか送れないため、HTTPSアダプターを使用します。Addressに受信側のODataサービスのURIを、Request Headersに②で設定したContent-Typeを設定します。
image.png

3.3.2. デプロイ

デプロイするとたまっていたメッセージが処理され、キューからメッセージが消えます。
image.png
ODataサービスを確認すると、データが登録されています。
image.png

4. エラー時の動作

受信側が利用不可だった場合の動作について確認してみます。

4.1. JMSアダプターの設定

エラー時の動作を決めるパラメータはいくつかあります。

4.1.1. Inbound

Inboundで使用するアダプターでは以下の2つのパラメータが関連します。
image.png

  • Retention Threshold for Alerting (in d):この日数を超えてメッセージがキューに残っている場合にアラートを発生させる
  • Expiration Period (in d):この日数を超えてメッセージが残っている場合にメッセージを削除する

参考:Configure the JMS Receiver Adapter

4.1.2. Outbound

Outboundで使用するアダプターでは、RETRY DETAILSにあるパラメータが関連します。
image.png

  • Retry Interval (in m):リトライまでの待ち時間(分)を指定する
  • Exponential Backoff:チェックをつけた場合、リトライが失敗するたびに待ち時間が2倍になる
  • Maximum Retry Interval (in m):リトライまでの最大の待ち時間(分)を指定する(Exponential Backoffを設定した場合に設定)
  • Dead-Letter Queue:メッセージ処理がout-of-memory errorで停止したときにメッセージがブロックされ、その後2回送信が試みられる。ブロックされたメッセージはMessage Locksタイルからロックを解除できる

参考: Configure the JMS Sender Adapter

4.2. 動作確認

Retention Threshold for Alertingを1日、Expiration Period (in d)を2日に設定して動作確認してみます。想定では以下の動きになります。
image.png

  • エラー発生直後から1分後、2分後…とリトライし、リトライ間隔が60分になった以降は60分おきにリトライする
  • キューに格納されてから1日後にアラートが発生する(どのような形で?)
  • キューに格納されたから2日後にキューから削除される

4.2.1. 設定

InboundのJMS Adapterの設定を変更します。
image.png
Outboundのフローでエラーを発生させるため、CAPのサービスを停止しておきます。
image.png

4.2.2. 結果

エラー発生直後

エラー発生直後、キューのステータスはFailedになっています。
image.png

処理結果のログを見るとすでに複数回リトライされています。ただ、リトライ間隔が1分どころではありません。
image.png
よく見ると、1回のリトライで2つの処理が行われています。リトライ間隔は初回は約44秒と短めですが、以降は2分、4分と2倍になっていることが確認できました。
image.png
さらに時間が経過するとリトライ間隔は8分、16分と伸びていき、最後は60分で固定されました。
image.png

1日後

キューにメッセージが格納されてから24時間経過しました。相変わらず60分ごとにリトライが実行されています。
image.png
どこかにアラートが届くのかと思っていましたが、そのようなことはありませんでした。
ヘルプによると、

  • メッセージの登録日時にRetention Threshold for Alertingを足した日時がDue Atに設定される
  • Due Atを過ぎた場合、メッセージのステータスは"Overdue"になる

ということでしたが、Due Atを過ぎてもステータスはFailedのままでした。
image.png

ステータスの件は謎ですが、Retention Threshold for Alertingはアラートを発生させるのではなく、キューに期限をつけて期限が切れたキューがないかを運用者がチェックするためのものであるようです。

2日後

キューからメッセージが削除されました。
image.png

5. おわりに

この記事では、CPIのJMSアダプターを使って非同期な連携を実現する方法を紹介しました。一方のEvent MeshにはS/4HANAとの連携ができることや、CAPと簡単に接続ができるなどのメリットがあります。よって、実際にはやりたいことによって使い分けになるだろうと思われます。
私は個人的にはCPIが好きで、調べていくと割となんでもできてしまうところに魅力を感じます。今後もCPIが使えるケースを見つけていきたいと思います。

3
2
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
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?