2017-03-16 7 views
1

Oracle APEX 4.2를 사용하면 실행 프로세스에 DBMS_ALERT를 사용하는 페이지 프로세스가 있습니다.이 프로세스는 완료 또는 실패에 최대 1 분이 걸릴 수 있습니다.Oracle APEX 내 Oracle DBMS_ALERT 사용 방법

트리거가 실행되는 동안 진행 중에 DBMS_ALERT.signal 게시 알림이 표시됩니다.

내 질문은 오라클 APEX 4.2에서 페이지의 영역 또는 모달 내의 DBMS_ALERT에서 이러한 알림의 실행 진행 상황을 어떻게 표시 할 수 있습니까?

마지막으로 완료 될 때까지 작업이 실행 중일 때 이러한 모든 경고를 사용자에게 제공해야합니다. 예를 들어

각 광고는 사용자에게 제시되기 전에 이들 DBMS_ALERTS 각 통해 분명히

Started Job... 
Waiting on resources... 
Processing job... 
Job completed successfully. 

수초가 될 수있다.

오라클 APEX 내에서 이러한 경고를 수집하고 사용자를 표시하는 방법을 확실히 모릅니다.

감사합니다.

답변

0

나는 apex.oracle.com에서 데모를 설정했지만 dbms_alert에서 실행 권한이 필요하므로 텍스트 전용이어야합니다.

전체 설정에서 상당히 멀리 갈 수 있으므로 기본 설정으로 생각해 보겠습니다. 예를 들어, 하나의 경고 만 처리했습니다. 샘플에서는 여러 이벤트를 사용하여 여러 가지 진행 경고를 포착 할 수 있습니다. 클라이언트 (ajax 응답)에 무엇인가를 반환하기 위해서는 ajax 콜백이 '닫혀 있어야'하는 단순한 이유 때문입니다. 그러므로 경고를 받고 그것을 반환하기를 원하면 버퍼에 기록해야하며 반환해야합니다. 즉, 이벤트 듣기도 중단됩니다 (꼭 읽어야합니다 : 정점에 있어야합니다!).

다음과 같은 흐름을 고려하십시오. ajax 호출을 작성하고 이벤트에 관심을 등록하는 ajax 콜백 프로세스가 있습니다. 그런 다음 경고가 발생할 때까지 기다립니다. 그것을 잡아서 http 버퍼 (htp.p)에 써서 그것을 돌려 준다. 그것이 코드의 끝이고 꼭지점은 버퍼를 플러시 할 것이고, 아약스 호출은 응답을 받으면 그 리턴을 관리 할 수 ​​있습니다.
apex는 연결 풀링을 사용하며 데이터베이스 세션은 직접 연결되지 않고 항상 재사용됩니다. 당신은 'dirtied'데이터베이스 세션을 '떠나'싶지 않습니다. 너는 너의 경보 관심사를 역시 등록 취소해야 할 것이다. 또한 경고에 고유 한 ID를 사용하는 경우가 있습니다. 경고가 다른 (데이터베이스) 세션에 등록 될 수 있으므로 여러 사용자가 프로세스 진행 상황을 추적하는 데 사용할 수있는 페이지이면 다른 사용자의 경고를 방해하기를 원합니다.

그러나 관심의 대상이된다는 말은 다른 아약스 호출간에 "중단"이 발생한다는 것을 의미합니다. 여러 개의 경고를 듣고 싶을 때 이러한 경고가 매우 밀접하게 압축 될 수 있으므로 기회를 놓칠 수 있습니다. 2 개의 경보가 1ms 간격으로 떨어져 있다고 가정하면, 첫 번째 경보는 잡히고 ajax 호출로보고됩니다. 그러면 더 많은 경보를 수신하기 위해 즉시 새로운 호출을 시작해야합니다. 그러나 짧은 시간 동안 적극적인 청취자가 없었기 때문에 다음 번 경고가 누락되었을 수 있습니다. 이제는 동일한 처리기에서 여러 개의 경고를 발생시키는 문제 일 가능성이 높습니다. 여러 핸들러를 사용하고 동시에 모든 사람에게 아약스 호출을 시작하면 모든 처리가 완료됩니다. 물론 둘 다를위한 해결책이 있습니다.하나의 핸들러를 사용할 때만 컬렉션의 모든 경고를 잡아서 특정 경고에 대한 응답을 이미 보내고 있는지 또는 계속 체크인할지 여부를 확인해 볼 수 있습니다. 여러 핸들러를 사용하면 고유 한 ID를 사용하고 다른 상태로 접미어를 붙일 수 있습니다.

내 로컬 POC에서 사용한 실제 코드는 다음과 같습니다.

개요 : 3 개의 버튼이 있습니다. 하나는 경고 ID를 생성하는데, 하나는 시퀀스를 사용했습니다. 이벤트를 듣기 시작하는 또 다른 버튼, 그리고 경고를 보내기위한 또 다른 버튼. NEW_ALERT_ID 단추

JS 번호 :

apex.server.process("NEW_ALERT").done(function(pdata){ 
$s("P1_ALERT_ID",pdata.alertId); 
}) 
START_LISTEN 단추

JS 번호 :

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? 
    } 
}); 
SEND_ALERT 단추

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를 얻을 그럼 난에서 다음 듣고 시작하고 줄 것 어떤 점에서 나는 경고를 보낼 것이다 (또는 아님). 그것은 골격이지만 실제 설정에서 더 세분화가 필요합니다.

+0

귀하의 자세한 답변에 진심으로 감사드립니다. 좀 더 자세히 살펴보고 필자의 요구 사항을 어떻게 구현할 수 있는지 살펴 보겠습니다. 내가 겪고 있던 문제는 내가 첫 번째 경고를 되 돌리는 것이었지만 그 다음에 더 이상의 경고를 폴링하는 방법을 확신하지 못했습니다. 어쨌든, 나는 너의 계단을 살펴볼 것이다. 다시 한번 감사드립니다. – tonyf

+0

@tonyf right - 그게 문제일지도 모르겠다. 문제는 실제로 폴링을 유지하는 것입니다. 폴링이 완료 될 때마다 새 통화를 시작해야하기 때문입니다. 그렇게 할 수있는 것은 많지 않습니다. 바로 꼭지점이 작동하는 방식입니다. 채널이 열리지 않고 가끔씩 정보를 반환하는 경우도 있습니다. 짧은 시간이 경고를 기다리는 코드 조각이없는 곳에서 발생할 수 있습니다. 그것은 기본적으로 긴 폴링입니다. 정보를 잃고 싶지 않으면 모든 정보를 저장하고 거기에서 검색 할 수있는 컬렉션과 같은 중간 시스템이 필요합니다. – Tom