2008. 10. 8. 15:28

[oracle]Broken된 Job을 자동으로 재실행 시키는 방법

--------------------------------------------------------------------------------
BROKEN된 JOB을 자동으로 재실행 시키는 방법
=========================================


1. broken job
~~~~~~~~~~~~~~
Oracle에서 특정 작업을 주기적으로 실행시키기 위해서는 job을 이용하게 된다.
이것은 snp라는 background process가 각 job의 interval간격으로 작업을 실행
하는데, snapshot과 같은 것이 job의 대표적인 예이며, dbms_job package를
이용하여 직접 job을 등록 및 관리, 삭제가 가능하다.

이러한 job이 문제가 발생하여 수행이 오류가 발생하면 1분, 2분, 4분, 8분과
같은 간격으로 자동으로 재실행을 하게 되고, 이 주기가 해당 job의 inerval보다
크게 되면 그때부터는 interval간격마다 job을 실행하도록 시도한다. job의
interval이 1분보다 작으로 interval간격대로 시도하고, 예를 들어 interval이
2분 20초마다이면, 1분, 2분, 이후에는 2분 20초 마다씩 새로 fail된 job을
실행해 본다. 이렇게 fail이 발생한 job을 자동으로 재실행하는 것은 최대 16번
이며, 16번 시도후에는 job이 broken상태가 되어 더 이상 snp process는 시도를
하지 않게 된다.

oracle이 이렇게 16번 시도 후 job을 broken상태로 하는 이유는 16번 시도 때까지
문제가 해결되지 않은 job이라면, 예를 들어 network이 장시간 down되어 snapshot
refresh가 안 되는 것과 같이 문제가 장기화될 가능성이 많고 그러한 job을 계속
시도해 보는 것 자체가 cpu를 많이 소모하는 낭비되는 작업이라는 판단 때문이다.

그러나 일단 job이 broken되면, 그 job을 fail 상태로 만든 원인이 제거된 후에도
여전히 실행되지 않은 상태로 있게 되어 db admin이 수시로 broken된 job이 있는
지를 확인하고 manual하게 dbms_job.run등을 실행하여 다시 실행하도록 할 필요가
있다.

이러한 db admin 작업을 덜고 database 자체에서 broken job에 대해서도 계속
run을 시도하고자 하는 경우 이 문서를 이용하여 작업하면 된다.


2. dba_jobs view에 대해서
~~~~~~~~~~~~~~~~~~~~~~~~~~

dba_jobs(혹은 user_jobs)는 등록된 job에 관한 여러가지 정보를 사용자게 제공
한다.

특히 job의 broken과 관련하여 중요한 몇개의 column에 대해서 살펴본다.

broken : 해당 job이 broken되었으면 Y, 그렇지 않으면 N로 나타난다.
failures : job이 시도되었으나 fail된 숫자이다. 이 숫자가 16이 되면 broken이
Y가 되어 더 이상 snp process는 시도하지 않게 되어 이 숫자도
증가가 되지 않는다.
단, dbms_job.run을 user가 manual하게 실행해도 여전히 문제가 발생
하면 이 숫자가 이미 16이상이라도 시도할 때마다 계속 1씩 증가한다.

next_date: job이 다음에 실행될 시간이다.
job이 실행을 시작하는 시점에 last_date + interval = next_date로
계산한 후 job 실행이 끝나면 (혹은 오류 발생 후) 시작 시점에
계산된 next_date값이 dba_jobs에 기록되어 확인이 가능해 진다.
이 시간이 과거로 되어 있으면, failures가 0이고 broken이 N이라
하더라도 snp는 그 job을 run하려고 시도하지 않는다.

this_date: 이것은 현재 실행되는 job이 실행을 시작한 시간을 나타낸다. 이미
실행이 끝난 job이라면 이 부분은 null로 나타나면 이 컬럼에 값이
있는 job에 대해서는 dba_jobs_running에도 정보가 나타난다.


3. broken된 job을 실행되도록 하는 procedure

먼저, broken된 job을 찾아 broken을 false로 만들어 주고 snp가 다시 실행하도록
next_date를 지정해 주는 procedure를 만든다.
이 procedure는 아래 3-2와 같으며 수행한 기록을 남기기 위해 job_log라는
table을 만들었는데 이 부분은 빼도 무관하다.

3-1 log table 생성
아래 procedure를 실행시키기 전에 먼저 이와 같이 table을 만든다.

SQL> create table job_log (jobno number,
jobname varchar2(30),
jobdate date);

3-2 broken job을 snp가 다시 실행하도록 하기 위해 다음과 같은 release_job을
관리하고자 하는 job의 owner에서 생성한다.

(1) broken job을 선택할 때 dba_jobs 대신에 user_jobs를 이용한다.
dbms_job package는 항상 해당 owner의 job만을 대상으로 작동하므로,
dba_jobs를 확인하고 보이는 job에 대해서 연산하면 owner가 아닌 경우
그러한 job이 없다는 오류가 발생하게 된다.

(2) dbms_job.run을 바로 실행하지 않은 이유는 dbms_job.run은 procedure
내에서 call하지 못하도록 정의되어 실제 사용하면 오류가 발생하거나
수행이 되지 않는다.

(3) broken='Y' 뿐 아니라 failures가 15이상인 것을 함께 check하는 이유는
이 procedure로 인해 일단 broken이 N로 변경된 상태에서 여전히 오류가
있으면 다음 수행 때 broken이 N여서 제외되기 때문이다.

(4) dbms_job.change의 세번째 argument가 next_date인데 이렇게 next_date를
원하는 시간, 혹은 약간의 미래로 맞추어 놓아야 release_job이 수행된
이후 snp가 이 시간에 broken으로 모아진 job을 실행하게 된다.

(5) 결국 broken으로 선택된 job들을 release_jobs가 수행될 때마다 한번씩
snp process로 하여금 다시 시도되도록 지정되어 진다.

(6) procedure source
create or replace procedure release_jobs as
cursor my_broken_jobs is
select job, what from user_jobs where broken = 'Y' or failures > 15;
begin
for broken_jobs in my_broken_jobs
loop
begin
dbms_job.broken(broken_jobs.job,FALSE);
dbms_job.change(broken_jobs.job, null, sysdate+1/1440, null);
insert into job_log values (broken_jobs.job,
broken_jobs.what,
sysdate);
commit;
Exception
when others then
null;
end;
end loop;
end;
/


4. release_jobs를 job으로 등록한다.

위에서 정의한 release_job을 job으로 등록하여 broken된 job을 찾아 실행해주는
작업 자체가 주기적으로 실행되도록 한다.
release_jobs 자체는 network을 타거나 space를 필요로 하는 등의 작업이 아니라,
fail이 발생할 우려는 거의 없다.
이 release_jobs를 등록한 job의 next_date가 미래이고 fail이 없는지만 확인하면,
나머지 broken job들은 여기에서 등록된 job이 관리하게 된다.

SQL>variable job number;
SQL>exec dbms_job.submit(:job, 'RELEASE_JOBS;',sysdate,'sysdate+1/1440');
SQL>exec dbms_job.run(:job);
SQL>commit;
 
출처 : http://kr.blog.yahoo.com/jhoony73/590306.html?p=1&pm=l