2015-02-16 3 views
5

Использование Oracle 11,2Как ждать DBMS_SCHEDULER рабочих мест, чтобы закончить

Привет,

Вот что я хочу сделать: Я планирования заданий с использованием DBMS_SCHEDULER. Количество заданий для расписания не фиксировано, и одновременно должно выполняться максимум 4 задания. Процедура планирования заданий должна ждать завершения всех заданий. Если одно задание не выполняется, процедура «расписание» также должна завершиться неудачей, и все оставшиеся запланированные задания должны быть удалены из планировщика.

В настоящее время мне пришлось спать и опросить таблицу user_scheduler_jobs в цикле.

Я новичок в PL/SQL и достаточно неопытный поэтому, пожалуйста, не быть слишком жестким на меня;)

Вот мой код до сих пор.

Первый фрагмент кода для планирования работ:

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; 

Процедура для ожидания до последних четырех рабочих мест 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; 

Это делает трюк, но это, кажется, как-то ужасный хак.

Не существует лучшего способа:

  1. Подождите, пока все рабочие не закончили.
  2. Просто запустите сразу четыре задания и запустите новый, как только закончится одно из рабочих заданий.
  3. Выбросить исключение, если одно задание не работает или не работает.
+3

Я бы использовал существующие функции, доступные для dbms_scheduler. Для # 1, посмотрели ли вы на цепи (http://docs.oracle.com/cd/B28359_01/appdev.111/b28419/d_sched.htm#CHDCJFCI)? # 2 Вы посмотрели на изменение job_queue_processes? –

+0

Что сказал Патрик - ознакомьтесь с механизмом цепей планировщика – thatjeffsmith

+0

Спасибо за ваши комментарии. К сожалению, я не могу использовать job_queue_processes, потому что я на общей БД, и они не позволяли мне использовать «alter system .....». Мое понимание цепочки работы заключается в том, что она позволяет мне определить что-то вроде «делать первые 4 задания» -> «Следующие 4 задания» -> «Следующие 4 задания» и т. Д., Но не нравится «начать 4 задания и как только как один закончен, начните следующий ». Моя цель заключается в том, что в любой момент времени выполняются четыре задания. Я также подумал о том, чтобы использовать DBMS_ALERT для ожидания Джобса, что, по крайней мере, немного снизило бы накладные расходы на кодирование. –

ответ

0

Используйте dbms_alert или dbms_pipe для отправки/получения информации о начале/окончании работы. Запросить таблицу заданий можно только в том случае, если вы не получили информацию в ожидаемое время.

+0

Эта труба или предупреждение работает только в том случае, если отправитель и получатель находятся в одном экземпляре.AQ будет лучшим выбором, что позволит ему работать в RAC. –

0

Oracle Scheduler использует Oracle Rersource Manager сильно, просто отправьте свои задания, определенные с уведомлением о конце, и у вас есть задача, ожидающая вашего события Q, которое учитывает задание, которые были отправлены, и заданий, которые были завершены.

Вы используете диспетчер ресурсов Oracle для управления максимальным количеством заданий для одновременной работы. Это также будет основываться на общей нагрузке на базу данных, защищая других пользователей от системы, заполненной заданиями.

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; 
Смежные вопросы