2024年7月2日火曜日

DBMS_PIPEを呼び出し異なるADB間でメッセージをやり取りする

ADBのOracle Database 23ai上でDBMS_PIPEを呼び出し、異なるインスタンス間でメッセージをやり取りしてみます。

DBMS_PIPE自体はオラクル・データベースに古くから提供されているパッケージのようですが、私は使うのは初めてです。これまでは単一インスタンス内で共有メモリを介したメッセージのやり取りだけが可能でした。

Autonomous Databaseの23aiでは、メッセージの保存先にオブジェクト・ストレージのバケットを指定することにより、異なるインスタンス間でのメッセージのやり取りができるようになりました。

以下のように動作する簡単なAPEXアプリケーションを作ってみました。異なるインスタンスで同じAPEXアプリケーションを実行し、メッセージをやり取りしています。


実装するにあたって、以下のオラクルのドキュメントを参考にしています。

また、以下の記事も参考にしました。ただし、以下の記事では、セットアップが完了していません。実装中にこの記事と同じエラー(ORA-20404)が発生したのですが、何故か、エラーが発生しなくなりました。今の所、回避手順は不明です。バケット内にlockファイルが無いというエラーだったのですが、バケット内にlockファイルは残っていて、それを手作業で消したのが良かったのかもしれません。
Persistent, cross database and cross region pipe in Oracle Database 23ai
https://technology.amis.nl/oracle/persistent-cross-database-and-cross-region-pipe-in-oracle-database-23ai/

以下より実装手順を紹介します。

アプリケーションを作る前に、DBMS_PIPEでメッセージのやり取りを行うための準備をします。

APEXのワークスペース・スキーマはデフォルトではパッケージDBMS_CLOUDとDBMS_PIPEの実行権限を持っていないため、ユーザーADMINでGRANT文を実行し、権限を付与します。

grant execute on dbms_cloud to <APEXワークスペース・スキーマ>;
grant execute on dbms_pipe to <APEXワークスペース・スキーマ>;


続いて、オブジェクト・ストレージにバケットを作成します。今回の例ではpipeというバケットを作成しています。バケットのURLは以下のようになります。バケット名が異なる場合は、pipeの部分を変更します。

https://[ネームスペース].objectstorage.[リージョン].oci.customer-oci.com/n/[ネームスペース]/b/pipe/o/


オブジェクト・ストレージにアクセスできるユーザーを作成し、そのユーザーのAPIキーを作成します。今回はユーザーはapex_api_agentとしています。

APIユーザーの作成については、以下の記事が詳しいです。
APEXからOCIオブジェクト・ストレージを操作する(1) - APIユーザーの作成


APIキーの追加時に取得したuser_ocidtenancy_ocidprivate_keyfingerprintの情報より、DBMS_CLOUD.CREATE_CREDENTIALを呼び出し、データベースにクリデンシャルを作成します。以下の例ではcredential_nameORACLE_API_AGENTとしています。


あらかじめ、パブリック・パイプのPIPE_C2Pを作成します。
declare
    l_status INTEGER;
begin
    l_status := DBMS_PIPE.CREATE_PIPE(
        pipename => 'PIPE_C2P'
        ,private => false
    );
end;

以上で準備は完了です。

空のAPEXアプリケーションを作成します。名前Sample DBMS_PIPEとします。

メッセージのやり取りは、ホーム・ページに実装します。


アプリケーション定義置換として、クリデンシャルバケットパイプの名前を設定します。

クリデンシャルは置換文字列CREDENTIAL_NAMEバケットBUCKET_URLパイプPIPE_NAMEの置換値として設定します。


ホーム・ページには2つのボタンSEND_MESSAGERECEIVE_MESSAGE、それとメッセージを入力するテキスト領域のページ・アイテムP1_MESSAGEを配置します。


ボタンSEND_MESSAGEを押したときに実行されるプロセスとしてSend Messageを作成し、以下のコードを記述します。



ボタンRECEIVE_MESSAGEを押したときに実行されるプロセスとしてReceive Messageを作成し、以下のコードを記述します。



以上でアプリケーションは完成です。同じ手順で異なるインスタンスにクリデンシャルやパイプを作成し、APEXアプリケーションをエクスポート/インポートすると、記事の先頭のGIF動画のように、メッセージのやり取りができます。

双方ともAutonomous Databaseの場合、インスタンス間での通信手段は他にもあります。データベース・リンクを経由したDBMS_AQによる通信は、DBMS_PIPEよりも高機能です。

DBMS_CLOUDパッケージを導入することで、オンプレの23aiともメッセージのやり取りができるかと考えて試してみましたが、できませんでした。オンプレ版のデータベースへのDBMS_CLOUDのインストールはサポートのドキュメントHow To Setup And Use DBMS_CLOUD Package (ドキュメントID 2748362.1)で紹介されていますが、 「This package is supported in Oracle Database 19c beginning with 19.9 and in Oracle Database 21c beginning with 21.3.」となっていて、23が含まれていません。そのあたりに問題がありそうです。

今回作成したAPEXアプリケーションのエクスポートを以下に置きました。
https://github.com/ujnak/apexapps/blob/master/exports/sample-dbms-pipe.zip

Oracle APEXのアプリケーション作成の参考になれば幸いです。