2015-02-16 15 views
5

Korzystanie z Oracle 11.2Jak czekać na DBMS_SCHEDULER pracy, aby zakończyć

Witam,

Oto co chcę zrobić: Mam szeregowanie zadań przy użyciu DBMS_SCHEDULER. Liczba zadań do zaplanowania nie jest stała, a jednocześnie powinno działać maksymalnie 4 zadania. Procedura planowania zadań powinna odczekać, aż wszystkie zadania zostaną zakończone. Jeśli jedno zadanie zakończy się niepowodzeniem, procedura "harmonogramu" również powinna zakończyć się niepowodzeniem, a wszystkie pozostałe zaplanowane zadania powinny zostać usunięte z harmonogramu.

Obecnie musiałem spać i sondować tabelę user_scheduler_jobs w pętli.

Jestem nowy w PL/SQL i raczej niedoświadczony więc proszę nie być zbyt trudne na mnie;)

Oto mój kod do tej pory.

Pierwszy fragment do planowania zadań:

BEGIN 
    FOR r IN (SELECT p_values FROM some_table WHERE flag = 0) 
    LOOP 
    -- count running jobs 
    SELECT count(*) INTO v_cnt 
    FROM user_scheduler_jobs 
    WHERE job_name LIKE 'something%'; 

    /* 
    If max number of parallel jobs is reached, then wait before starting a new one. 
    */ 
    WHILE v_cnt >= l_max_parallel_jobs 
    LOOP 

     dbms_lock.sleep(10); 

     SELECT count(*) INTO v_cnt 
     FROM user_scheduler_jobs 
     WHERE job_name LIKE 'something%' AND state = 'RUNNING'; 

     SELECT count(*) INTO v_cnt_failures 
     FROM user_scheduler_jobs 
     WHERE job_name LIKE 'something%' AND state = 'FAILED' OR state = 'BROKEN'; 

     IF v_cnt_failures > 0 THEN RAISE some_exception; END IF; 

    END LOOP; 

    -- Start a new Job 
    v_job_name := 'something_someting_' || p_values; 
    v_job_action := 'begin user.some_procedure(''' || r.p_values || '''); end;'; 

    dbms_scheduler.create_job(job_name => v_job_name, 
           job_type => 'PLSQL_BLOCK', 
           job_action => v_job_action, 
           comments => 'Some comment ' || v_job_name, 
           enabled => FALSE, 
           auto_drop => FALSE); 

    dbms_scheduler.set_attribute(NAME => v_job_name, 
           ATTRIBUTE => 'max_failures', 
           VALUE => '1'); 

    dbms_scheduler.set_attribute(NAME => v_job_name, 
           ATTRIBUTE => 'max_runs', 
           VALUE => '1'); 

    dbms_scheduler.enable(v_job_name); 

    v_job_count := v_job_count + 1; 

    -- array for all jobs 
    v_jobs_aat(v_job_count) := v_job_name; 

    END LOOP; 

    -- ... Wait till all jobs have finisched. 

    check_queue_completion(v_jobs_aat); -- see procedure below 
END; 

Procedura czekając aż czterech ostatnich miejsc pracy mają finisched:

PROCEDURE check_queue_completion(p_jobs_aat IN OUT t_jobs_aat) AS 
    v_state user_scheduler_jobs.state%TYPE; 
    v_index PLS_INTEGER; 
    v_done BOOLEAN := TRUE; 

    -- Exceptions 
    e_job_failure EXCEPTION; 
BEGIN 

    WHILE v_done 
    LOOP 

    v_done := FALSE; 

    FOR i IN p_jobs_aat.first..p_jobs_aat.last 
    LOOP 

     SELECT state INTO v_state FROM user_scheduler_jobs WHERE job_name = p_jobs_aat(i); 

     --dbms_output.put_line('Status: ' || v_state); 

     CASE 

     WHEN v_state = 'SUCCEEDED' OR v_state = 'COMPLETED' THEN 
     dbms_output.put_line(p_jobs_aat(i) || ' SUCCEEDED'); 
     dbms_scheduler.drop_job(job_name => p_jobs_aat(i), force => TRUE); 
     p_jobs_aat.delete(i); 

     WHEN v_state = 'FAILED' OR v_state = 'BROKEN' THEN 
     --Exception auslösen 
     dbms_output.put_line(p_jobs_aat(i) || ' FAILED'); 
     RAISE e_job_failure; 

     WHEN v_state = 'RUNNING' OR v_state = 'RETRY SCHEDULED' THEN 
     NULL; 
     dbms_output.put_line(p_jobs_aat(i) || ' RUNNING or RETRY SCHEDULED'); 
     v_done := TRUE; 

     /*DISABLED, SCHEDULED, REMOTE, CHAIN_STALLED*/ 
     ELSE 
     dbms_output.put_line(p_jobs_aat(i) || ' ELSE'); 
     dbms_scheduler.drop_job(job_name => p_jobs_aat(i), force => TRUE); 
     p_jobs_aat.delete(i); 
     END CASE; 

    END LOOP; 

    hifa.gen_sleep(30); 

    END LOOP; 

    IF p_jobs_aat.count > 0 THEN delete_jobs_in_queue(p_jobs_aat); END IF; 

    EXCEPTION WHEN e_job_failure THEN 
    delete_jobs_in_queue(p_jobs_aat); 
    RAISE_APPLICATION_ERROR(-20500, 'some error message'); 

END check_queue_completion; 

To załatwia sprawę, ale wydaje się, że jakiś okropny hack.

nie Czy istnieje lepszy sposób:

  1. Poczekaj, aż wszystkie zadania zostały zakończone.
  2. Po prostu uruchom cztery zadania naraz i rozpocznij nowe, gdy tylko jedno z zadań zostanie zakończone.
  3. Wyrzuć wyjątek, jeśli jedno zadanie nie działa lub jest uszkodzone.
+3

Chciałbym wykorzystać istniejące funkcje dostępne dla dbms_scheduler. Dla # 1, Czy obejrzałeś łańcuchy (http://docs.oracle.com/cd/B28359_01/appdev.111/b28419/d_sched.htm#CHDCJFCI)? # 2 Czy przyjrzałeś się modyfikacjom procesów job_queue_questes? –

+0

Co powiedział Patrick - sprawdź mechanizm łańcucha harmonogramów – thatjeffsmith

+0

Dzięki za komentarze. Niestety nie mogę użyć job_queue_processes, ponieważ jestem na wspólnym DB i nie pozwolą mi użyć "alter system .....". Moje rozumienie łańcuchów pracy polega na tym, że pozwala mi to zdefiniować coś w stylu "wykonaj pierwsze 4 zadania" -> "następne 4 zadania" -> "następne 4 zadania" i tak dalej, ale nie "rozpocznij 4 prace i tak szybko" jak skończysz, zacznij następny ". Moim celem jest, aby w danym momencie działały cztery zadania. Myślałem także o używaniu DBMS_ALERT do oczekiwania na zadania, które przynajmniej zmniejszą nieco obciążenie związane z kodowaniem. –

Odpowiedz

0

Użyj polecenia dbms_alert lub dbms_pipe, aby wysyłać/odbierać informacje o rozpoczęciu/zakończeniu zadania. Zapytanie tabeli zadań tylko wtedy, gdy nie otrzymasz informacji w oczekiwanym czasie.

+0

Ta rura lub alert działa tylko wtedy, gdy nadawca i odbiorca znajdują się w tym samym wystąpieniu.AQ byłby lepszym wyborem, dzięki czemu będzie działał w RAC. –

0

Oracle Scheduler używa Oracle Rersource Manager, po prostu prześlij swoje zadania, zdefiniowane z powiadomieniem końcowym i mają zadanie czekające na twoje wydarzenie Q, które zlicza przesłane prace i zadania, które zostały zakończone.

Używasz menedżera zasobów Oracle do kontrolowania maksymalnej liczby zadań do uruchomienia jednocześnie. Będzie to również oparte na całkowitym obciążeniu bazy danych, chroniąc innych użytkowników przed systemem zalewanym przez zadania.

0
DECLARE 
    cnt NUMBER:=1; 
BEGIN 
    WHILE cnt>=1 
    LOOP 
    SELECT count(1) INTO cnt FROM dba_scheduler_running_jobs srj 
    WHERE srj.job_name IN ('TEST_JOB1','TEST_JOB2'); 
    IF cnt>0 THEN 
     dbms_lock.sleep (5); 
    END IF; 
    END LOOP; 
    dbms_output.put_line('ASASA'); 
END; 
Powiązane problemy