私はapex.oracle.comでデモを設定しましたが、dbms_alertで実行許可が必要なので、テキストのみでなければなりません。
あなたはセットアップ全体でかなり遠くに行くことができるので、私はこれを基礎として考えています。 たとえば、1つのアラートで作業しています。サンプルでは、複数のイベントを使用してさまざまな進捗アラートをキャッチすることができます。これは、クライアントに何かを返す(ajaxレスポンス)ためには、ajaxコールバックを '閉じ'なければならないという単純な理由によるものです。したがって、アラートをキャッチしてそれを返す場合は、バッファに書き込む必要があり、それを返す必要があります。これは、イベントの聴取をやめることを意味します(読んでください:頂点で、あなたは!)。
このような流れを考えてみましょう。あなたはajax呼び出しを行い、イベントに関心を登録するajaxコールバックプロセスを持っています。その後、アラートが発生するのを待ちます。 httpバッファ(htp.p
)に書き込むことでそれを捕まえて返します。それがコードの終わりで、頂点がバッファをフラッシュすると、ajaxコールが応答を受け取り、そのリターンを管理することができます。
apexは接続プーリングを使用し、データベースセッションは直接リンクされず、常に再利用されます。あなたは、「汚れた」データベースセッションを「離れる」ことを望まない。アラートの関心も登録解除する必要があります。これにより、アラートに一意のIDを使用するケースもあります。アラートは異なる(データベース)セッションに登録できるため、複数のユーザーがプロセスの進行状況を追跡するために使用できるページであれば、他のユーザーのアラートに干渉するようにしてください。
しかし、興味のあるこの瞬間的な性質は、異なるajax呼び出しの間に「中断」が存在することを意味します。複数の警告を聞きたい場合、これらの警告が非常に緊密に詰め込まれている可能性があります。 2つのアラートが1ミリメートル離れているとします。最初のアラートは捕捉され、アラートを受信するためにすぐに新しいコールを開始する必要があるajaxコールに報告されます。しかし、その短い時間にアクティブリスナーがいなかったので、その次のアラートが見逃された可能性があります。これは、同じハンドラの下で複数のアラートを起動する場合にのみ発生する可能性があります。複数のハンドラを使用し、同時にすべてのハンドラを開始する場合は、すべて時間通りに処理されます。もちろん、両方のソリューションがあります。1つのハンドラを使用すると、コレクション内のすべてのアラートをキャッチして、特定のアラートに対する応答を既に送信していて、チェックインを続行するかどうかを確認できます。複数のハンドラを使用すると、一意のIDを使用して、異なるステータスでサフィックスを付けることができます。
ここに私のローカルPOCで使用した実際のコードがあります。
概要:3つのボタンがあります.1つは、シーケンスを使用するアラートIDを生成します。イベントのリッスンを開始するもう1つのボタン、およびアラートを送信するもう1つのボタン。
NEW_ALERT_IDボタンのJSコード:START_LISTENボタンの
apex.server.process("NEW_ALERT").done(function(pdata){
$s("P1_ALERT_ID",pdata.alertId);
})
JSコード:SEND_ALERTボタンの
apex.server.process("LISTEN_ALERT",{x01:$v("P1_ALERT_ID")},{timeout:(31*1000)})
.done(function(pdata){
if (pdata.success){
alert('Caught alert: ' + pdata.message);
} else {
alert("No alerts caught during wait on database. You may want to continue listening in...")
}
})
.fail(function(jqXHR, textStatus){
if(textStatus === 'timeout')
{
alert('Call should have returned by now...');
//do something. Try again perhaps?
}
});
JSコード:
apex.server.process("SEND_ALERT",{x01:$v("P1_ALERT_ID")},{dataType:"text"});
AJAXコールバックプロセス:
NEW_ALERT:
htp.p('{"alertId":'||alert_seq.nextval()||'}');
がLISTEN_ALERT:
declare
alert_id number := apex_application.g_x01;
msg varchar2(2000);
stat pls_integer;
keep_looping boolean := true;
insurance binary_integer := 0; -- prevent an infinite loop
onecycle binary_integer := 3; -- one cycle of waiting, in seconds
maxcycles binary_integer := 10; -- in this session, the max amount of cycles to wait
begin
dbms_alert.register(alert_id);
while keep_looping
loop
insurance := insurance + 1;
dbms_alert.waitone(alert_id, msg, stat, onecycle);
if stat = 1 then
apex_debug.message('timeout occured, going again');
else
apex_debug.message('alert: '||msg);
keep_looping := false;
end if;
exit when insurance = maxcycles;
end loop;
if keep_looping then
-- we waited a really long time now. It may be a good idea to return this info to the client and let it start a new call
htp.p('{"success":false,"message":"No alert during wait on database"}');
else
htp.p('{"success":true,"message":"'||msg||'"}');
end if;
end;
SEND_ALERT:
declare
alert_id number := apex_application.g_x01;
begin
dbms_alert.signal(alert_id, 'alert sent at '||to_char(systimestamp, 'HH24:MI:SS FF6'));
end;
だから、私は最初に私が聞くことを開始し、その後に思い、アラートのIDを取得したいです私は警告を送信する(またはしない)いくつかのポイント。それはスケルトンですが、あなたの実際のセットアップではさらに改良が必要です。
は、あなたの詳細な対応に本当に感謝しています。私はそれを詳しく見て、自分の要求にどのように取り入れるかを見ていきます。私が経験していた問題は、最初のアラートを取り戻すことができましたが、その後、さらにアラートをポーリングする方法がわかりませんでした。とにかく、私はあなたの階段を見ていきます。再度、感謝します。 – tonyf
@tonyf right - 私はそれが問題だったかもしれないと思います。問題は「ポーリングを維持する」ことです。完了するたびに新しい通話を開始する必要があるためです。あなたができることはあまりありません。それはちょうど頂点の仕組みです - 時には情報を返すと同時にチャンネルを開いたままにすることはありません。これは、アラートを待っているコードを持っていないところで短期間で発生する可能性がある場所です。それは基本的に長いポーリングです。情報を失いたくない場合は、すべての情報を保存してそこから取得するためのコレクションなどの仲介システムが必要になります。 – Tom