Jeg ville oprette en demo på apex.oracle.com, men da du har brug for en eksekveringsbevilling på dbms_alert, skal den kun være tekstmæssig.
Du kan nå ret langt med hele opsætningen, så jeg vil betragte dette som grundlæggende ting at bygge videre på. For eksempel har jeg kun arbejdet med én advarsel. I dit eksempel vil du måske bruge flere hændelser til at fange de forskellige fremskridtsadvarsler. Dette er af den simple grund, at for at returnere noget til klienten (ajax-svaret), skal ajax-tilbagekaldet "lukkes". Så når du fanger en alarm og vil returnere den, skal du skrive til bufferen, og den skal returneres. Det betyder, at du også stopper med at lytte til begivenheden (læs:i apex, du burde!).
Overvej flowet som dette:du vil foretage et ajax-opkald og have en ajax-tilbagekaldsproces, som registrerer interesse for en begivenhed. Derefter venter du på, at der kommer en alarm. Du fanger den og returnerer den ved at skrive den i http-bufferen (htp.p
). Det er slutningen af koden, og apex vil tømme bufferen, ajax-opkaldet vil derefter opfange svaret, og du vil være i stand til at administrere denne tilbagevenden.
Glem dog ikke:apex bruger forbindelsespooling og database sessioner er ikke forbundet direkte, men genbruges snarere hele tiden. Du ønsker ikke at 'lade' en databasesession 'snavset'. Du skal også afmelde din alarm-interesse. Dette gør også et argument for at bruge unikke ID'er til advarsler - advarsler kan registreres i forskellige (database) sessioner, så hvis dette ville være en side, som flere brugere kan bruge til at følge forløbet af deres procesforløb, behøver du ikke vil have dem til at forstyrre andre brugeres advarsler.
Men denne flygtige karakter af interesse betyder også, at der vil være "afbrydelser" mellem forskellige ajax-opkald. Når du vil lytte efter flere advarsler, og disse advarsler kan være pakket meget tæt sammen, er der en chance for, at du går glip af en. Lad os sige, at 2 alarmer er placeret 1 ms fra hinanden:den første vil blive fanget, rapporteret til ajax-opkaldet, som skulle starte et nyt opkald med det samme for at lytte efter flere alarmer. Men da der ikke var nogen aktiv lytter i den korte tid, kan den næste alarm være gået glip af. Nu - dette er sandsynligvis kun et problem, hvor du affyrer flere advarsler under den samme handler. Hvis du ville bruge flere handlere og starte ajax-opkald for alle dem på samme tid, vil de alle blive håndteret i tide. Der er selvfølgelig løsninger til begge dele. Jeg forestiller mig, at når du kun bruger én handler, kan du fange alle alarmer i en samling og kontrollere, om du allerede har sendt et svar for en bestemt alarm eller ej, og om du skal fortsætte med at tjekke ind eller ej. Med flere handlere kan du bruge et unikt id og suffikse det med forskellige statusser.
Så her er noget faktisk kode, som jeg har brugt i min lokale POC.
Oversigt:Jeg har 3 knapper:1 til at generere et alarm-id, som jeg brugte en sekvens til. Endnu en knap til at begynde at lytte til en begivenhed, og endnu en knap til at sende en advarsel.
JS-kode for knappen NEW_ALERT_ID:
apex.server.process("NEW_ALERT").done(function(pdata){
$s("P1_ALERT_ID",pdata.alertId);
})
JS-kode for knappen START_LISTEN:
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-kode for knappen SEND_ALERT:
apex.server.process("SEND_ALERT",{x01:$v("P1_ALERT_ID")},{dataType:"text"});
AJAX tilbagekaldsprocesser:
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;
Så jeg ville først få et alarm-id, så begyndte jeg at lytte, og så på et tidspunkt ville jeg sende en advarsel (eller ej). Det er dog et skelet og vil have brug for yderligere forfining i din faktiske opsætning.