Ik zou een demo opzetten op apex.oracle.com, maar aangezien je een execute grant nodig hebt op dbms_alert, moet het alleen tekstueel zijn.
Je kunt vrij ver gaan met de hele opzet, dus ik beschouw dit als een basis om op voort te bouwen. Ik heb bijvoorbeeld maar met één waarschuwing gewerkt. In uw voorbeeld wilt u misschien meerdere gebeurtenissen gebruiken om de verschillende voortgangswaarschuwingen op te vangen. Dit is om de simpele reden dat om iets terug te sturen naar de klant (de ajax response) de ajax callback moet worden 'gesloten'. Dus wanneer u een waarschuwing ontvangt en deze wilt retourneren, moet u naar de buffer schrijven en deze moet worden geretourneerd. Dit betekent dat je ook stopt met luisteren naar het evenement (lees:in apex, dat zou je moeten doen!).
Beschouw de stroom als volgt:je voert een ajax-oproep en hebt een ajax-callback-proces dat interesse in een evenement registreert. Vervolgens wacht u op een waarschuwing. Je vangt het op en geeft het terug door het in de http-buffer te schrijven (htp.p
). Dat is het einde van de code en apex zal de buffer leegmaken, de ajax-aanroep zal dan het antwoord oppikken en u zult in staat zijn om die terugkeer te beheren.
Vergeet echter niet:apex gebruikt verbindingspooling en database sessies zijn niet direct gekoppeld, maar worden de hele tijd hergebruikt. U wilt een databasesessie niet 'vuil' laten. U moet uw alert-interesse ook uitschrijven. Dit pleit ook voor het gebruik van unieke ID's voor waarschuwingen - waarschuwingen kunnen worden geregistreerd in verschillende (database)sessies, dus als dit een pagina zou zijn die meerdere gebruikers kunnen gebruiken om de voortgang van hun proces te volgen, hoeft u dat niet te doen willen dat ze de waarschuwingen van andere gebruikers verstoren.
Deze vluchtige aard van interesse betekent echter ook dat er "onderbrekingen" zullen zijn tussen verschillende ajax-oproepen. Als u naar meerdere waarschuwingen wilt luisteren, en deze waarschuwingen kunnen heel dicht bij elkaar staan, bestaat de kans dat u er een mist. Stel dat 2 waarschuwingen 1 ms uit elkaar liggen:de eerste wordt opgevangen, gerapporteerd aan de ajax-oproep, die meteen een nieuwe oproep zou moeten starten om naar meer waarschuwingen te luisteren. Maar aangezien er in die korte tijd geen actieve luisteraar was, is die volgende waarschuwing mogelijk gemist. Nu - dit is waarschijnlijk alleen een probleem waarbij u meerdere waarschuwingen onder dezelfde handler afvuurt. Als je meerdere handlers zou gebruiken en ajax-oproepen voor al deze tegelijkertijd zou starten, zullen ze allemaal op tijd worden afgehandeld. Voor beide zijn natuurlijk oplossingen. Ik stel me voor dat wanneer je maar één handler gebruikt, je alle waarschuwingen in een verzameling kunt opvangen en kunt controleren of je al een reactie op een bepaalde waarschuwing hebt verzonden of niet en of je wilt doorgaan met inchecken of niet. Met meerdere handlers kunt u een unieke id gebruiken en deze met verschillende statussen toevoegen.
Dus hier is wat echte code die ik heb gebruikt in mijn lokale POC.
Overzicht:Ik heb 3 knoppen:1 om een alert-ID te genereren, waarvoor ik een reeks heb gebruikt. Een andere knop om te beginnen met luisteren naar een gebeurtenis, en nog een andere knop om een waarschuwing te sturen.
JS-code voor NEW_ALERT_ID-knop:
apex.server.process("NEW_ALERT").done(function(pdata){
$s("P1_ALERT_ID",pdata.alertId);
})
JS-code voor START_LISTEN-knop:
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-code voor SEND_ALERT-knop:
apex.server.process("SEND_ALERT",{x01:$v("P1_ALERT_ID")},{dataType:"text"});
AJAX terugbelprocessen:
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;
Dus ik zou eerst een waarschuwings-ID krijgen, dan zou ik beginnen te luisteren en op een gegeven moment zou ik een waarschuwing sturen (of niet). Het is echter een skelet en zal verdere verfijning nodig hebben in uw daadwerkelijke opstelling.