ラベル DBMS_PIPE の投稿を表示しています。 すべての投稿を表示
ラベル DBMS_PIPE の投稿を表示しています。 すべての投稿を表示

2024年7月3日水曜日

DBMS_PIPEのシングルトン・パイプを使ってAPEXアプリに掲示板を付ける

Oracle Database 23aiで提供されているパッケージDBMS_PIPEにて、シングルトン・パイプという機能がサポートされています。最大32,767バイトのカスタム・メッセージをキャッシュでき、高速にメッセージを取得できます。

シングルトン・パイプについては、Oracleの以下のドキュメントで説明されています。
https://docs.public.oneportal.content.oci.oraclecloud.com/ja-jp/iaas/autonomous-database-serverless/doc/autonomous-singleton-pipe.html

上記のドキュメントからはAutonomous Databaseでの23aiに限定されているように見えますが、シングルトン・パイプについてはOracle Database 23ai Free上でも動作することが確認できています。Oracle Database 23aiのDBMS_PIPEのもう一つの拡張機能、永続メッセージングに対するパイプの使用については、(パッケージDBMS_CLOUDに依存しているため)Autonomous Databaseの23aiに限定された機能のようです。

サンプル・データセットEMP/DEPTをインストールして、APEXアプリケーションを作成します。そのアプリケーションのすべてのページに掲示板のリージョンを作成し、メンテナンスの通知を表示します。


今回の機能はグローバル・ページと新たに追加したページに実装するため、どのようなアプリケーションを選んでも同じように作業ができます。

本記事での説明には、SQLワークショップサンプル・データセットに含まれるEMP/DEPTをインストールしたときに作成できるアプリケーションを使います。


データセットのインストールまたは更新を行うと、最後にアプリケーションの作成を呼び出すことができます。


アプリケーションの作成をクリックすると、アプリケーション作成ウィザードが開きます。機能は使わないため、すべてをチェックをクリックしてチェックをすべて外します

ページの追加をクリックし、空白ページを追加します。ページ名Noticeとします。

以上でアプリケーションの作成を行います。


アプリケーションが作成されます。


今回はコードの色々な箇所でパイプ名の指定があるため、アプリケーション定義置換文字列PIPE_NAMEとして、DBMS_PIPE.CREATE_PIPEを呼び出して作成するパイプの名前を設定します。

今回はパイプ名をBULLETIN_BOARDとします。


グローバル・ページ(ページ番号)に掲示板となるリージョンを作成します。

識別名前掲示板タイプとして動的コンテンツを選択します。ソースCLOBを返すPL/SQLファンクション本体として、以下を記述します。

DBMS_PIPE.RECEIVE_MESSAGEのtimeout0を指定し、メッセージの待機時間を0秒にします。l_statusに0が返されるときはキャッシュされたメッセージが存在します。待機時間は0秒ですがメッセージが存在しないときは、タイムアウトを意味する1が返されます。エラーの場合は1より大きい値が返されます。

l_statusが0のとき、キャッシュされたメッセージをunpackしリージョンに表示します。

レイアウトスロットBannerを選択し、掲示板をページの一番上に表示させます。外観テンプレートに装飾の無いBlack with Attributesを選択し、掲示板の見え方はシングルトン・パイプにキャッシュしたメッセージで決めるようにします。

サーバー側の条件タイプ言語PL/SQLを選択し、PL/SQL式として以下を記述します。

0 = dbms_pipe.receive_message(pipename => :PIPE_NAME,timeout => 0)

シングルトン・パイプにキャッシュされたメッセージが存在するときに限り、掲示板を表示します。


シングルトン・パイプにメッセージをキャッシュする、または、キャッシュをパージする機能を、ページNoticeに実装します。

掲示板に表示するメッセージを設定するボタンを作成します。

識別ボタン名SET_MESSAGEラベルSet Messageです。動作アクションはデフォルトのページの送信とします。


キャッシュされたメッセージをパージするボタンを作成します。

識別ボタン名PURGEラベルPurgeです。動作アクションはデフォルトのページの送信とします。レイアウト新規行の開始オフにし、ボタンSET_MESSAGEの右横に配置します。


メッセージを書き込むページ・アイテムを作成します。

識別名前P7_MESSAGEタイプテキスト領域を選択します。セッション・ステートストレージセッションごと(永続)を選択します。

掲示板に表示するメッセージはHTMLを想定しているため、このページ・アイテムにはHTMLを直接記述します。タイプリッチ・テキスト・エディタとして書式HTMLを選択すると、メッセージの記述にリッチ・テキスト・エディタを使うことができます。


すでにキャッシュされたメッセージがあれば、ページ・アイテムP7_MESSAGEをそのメッセージで初期化するプロセスを作成します。

レンダリング前ヘッダーの前にプロセスInitを作成します。ソースPL/SQLコードとして、以下を記述します。



プロセス・ビューを開きます。

メッセージをシングルトン・パイプにキャッシュするプロセスを作成します。

識別名前Set MessageソースPL/SQLコードとして、以下を記述します。
declare
    l_status integer;
begin
    dbms_pipe.pack_message(:P7_MESSAGE);
    l_status := dbms_pipe.send_message(:PIPE_NAME);
end;
サーバー側の条件ボタン押下時SET_MESSAGEを指定します。


シングルトン・パイプにキャッシュしたメッセージをパージするプロセスを作成します。

識別名前PurgeソースPL/SQLコードとして、以下を記述します。
begin
    dbms_pipe.purge(:PIPE_NAME);
end;
サーバー側の条件ボタン押下時PURGEを指定します。


以上でアプリケーションは完成です。

作成したアプリケーションを実行する前に、メッセージをキャッシュするシングルトン・パイプを作成します。pipenameBULLETIN_BOARDです。キャッシュの有効期限として引数shelflife3600秒を設定しています。
declare
    l_status integer;
begin
    l_status := dbms_pipe.create_pipe(
        pipename => 'BULLETIN_BOARD'
        ,private => true
        ,singleton => true
        ,shelflife => 3600
    );
end;

作成済みのパイプはv$db_pipesから確認できます。デフォルトではAPEXワークスペースにSELECT権限が与えられていないため、ユーザーADMINでSELECT権限を与えておく必要があります。

select * from v$db_pipes


DBMS_PIPE.CREATE_PIPEを再度呼び出すことにより、キャッシュの有効期限を変更することができます。すでにシングルトン・パイプが作成済みでもエラーは発生しないようです。

記事の先頭のGIF画像で設定しているメッセージは以下です。
<div style="background-color: var(--u-color-6)">
    <div class="u-flex u-align-items-center">
        <div class="margin-auto u-bold  margin-top-sm margin-bottom-sm">今晩、メンテナンスが予定されています。</div>
    </div>
</div>
今回の記事は以上になります。

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

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



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のアプリケーション作成の参考になれば幸いです。