ここで、Oracle Advanced Queueing の最初のステップを...
シナリオ: 次のステップを処理するために、非常に多くの複数の独立したプロセスが中央コントローラーに報告する実行中のアプリケーションがあります。簡略化されたプロセスは、cron または終了したばかりのプロセスのコールバックを介して開始されます。コールバックは、リモート ホストから http -> php -> DB を介して行われます。基本的には、プロセスがリモート ホストで終了した後に 1 回の http 呼び出しです。
完全なコントローラー ロジックは、シングルトンの概念を念頭に置いて pl/sql で記述されているため、同時に 1 つのプロセスのみがコントローラー ロジックを実行する必要があります。実際、すべての呼び出しの 99% でこれは必要ありませんが、現時点で変更できるものではありません (アーキテクチャ全般も同様です)。
これを確実にするために、実際には悪いミューテックス実装、疑似コードがあります
$mutex = false;
while( not $mutex )
{
$mutex = getMutex();
if( $mutex )
executeController();
else
sleep(5);
}
ここで、mutex は値 0 (=> "free") または 1 (=> "busy") を持つ 1 フィールド テーブルです。
この「美しい」構成の結果、ログ ファイルは「Hey! Mutex がありません! Waiting...」でいっぱいになります。そして、待機するプロセスが多ければ多いほど、次のプロセスを制御できずに待機する時間が長くなります。時々、負荷が非常に重くなり、Apache が最初に fork し、最終的に死ぬことがあります...
解決
したがって、私の最初の「操作」は、mutex を Oracle Advanced Queueing に置き換え、コントローラーを単一のコンシューマーとして使用することです。利点: Apache レイヤー内での「忙しい待機」はもう必要ありません。厳格な先着順です。
(すべての DB アクションは同じオラクル スキーマで実行されるため、これは標準オブジェクト、pl/sql メソッドでも実現できます。しかし、dbms パッケージがある場合、なぜ車輪を再発明するのでしょうか?)
私が読む限り、このコンテキストで listen-feature (キューに入れられたアイテムをポーリングする) を使用することは、registration-feaure (メッセージが到着したときにアクションをスケジュールすること) よりもはるかに優れています。
基本的にすべて正常に動作します。
- メッセージタイプを作成する
- キューテーブルを作成する
- キューを作成する
- キューを開始します
- USER をサブスクライバーとして追加
- エンキューの手順を作成する
- 処理とデキューの手順を作成する
- キューをリッスンし、メッセージが到着したときに「プロセスとデキュー」関数を呼び出す手順を作成します。
もちろん、リスナーは 24 時間年中無休でアクティブであるため、「待機」時間を指定しませんでした。一般に、一日の時間帯にもよりますが、彼は少なくとも数分ごと、より多くの場合は数秒ごと、時にはそれ以上の「やるべきこと」を得るでしょう。
ここに私の問題があります(実際に問題がある場合)、これまでに見つけた例に従って書きました:
CREATE OR REPLACE PROCEDURE demo_aq_listener IS
qlist dbms_aq.aq$_agent_list_t;
agent_w_msg sys.aq$_agent;
BEGIN
qlist(0) := sys.aq$_agent(USER, 'demo_aq_queue', NULL);
LOOP
dbms_aq.listen(agent_list => qlist, agent => agent_w_msg);
DEMO_AQ_DEQUEUE();--process & dequeue
END LOOP;
END;
/
プロシージャを呼び出すと、基本的に私が期待することを行います。「アップ」したままで、キューに入れられたメッセージを処理します。
しかし、これはこれを行う方法ですか?キューに入れられたメッセージがない場合はどうなりますか? dbms_aq.listen -routine または "できるだけ速くループする" 内で "スリープ" しているので、"ビジー待機" の別の方法を実装しただけですか? 到達しなかったタイムアウトがある可能性があります (おそらく oss レベルまたは他の場所で)。
キュー定義などを含む完全なコードは次のとおりです。 demo_dbms_aq_with_listener.sql
アップデート
さらなるテストを通じて、私は、私が望んでいたよりもはるかに大きな理解が不足しているように見えることに気付きました:(
「実行レベル」では、リスナーをまったく使用せず、デキュー関数をループするだけで同じ効果があります。最初/次のメッセージを待ちます
CREATE OR REPLACE PROCEDURE demo_aq_listener IS
BEGIN
LOOP
DEMO_AQ_DEQUEUE();
END LOOP;
END;
/
少なくともこれはテストが簡単で、呼び出すだけです
BEGIN
DEMO_AQ_DEQUEUE();
END;
/
また、最初のメッセージを待つだけです。これにより、リスナーが必要かどうか、そして私がやっていることはまったく意味があるかどうか、私は完全に混乱したままになります:(
結論
すべてのメッセージを同じ方法で処理できる単一のコンシューマーがあるため、リスナーはまったく必要ありません。
しかし、キー/コアの質問は同じままです: DBMS_AQ.DEQUEUE を「おそらくアクティブな待機」でループに保持しても、1 日中短い間隔でメッセージを受信することを知っていても問題ありませんか?
(上記のリンクされた sql-file に DEMO_AQ_DEQUEUE() があります)