Могу ли я получить возвращаемое значение каким-либо образом из задания планировщика СУБД?

У меня есть веб-страница (сгенерированная через PL/SQL), которая позволяет кому-то включать или выключать удаленное устройство. Они представлены со списком устройств, и они используют флажки, чтобы выбрать те, чтобы переключаться. UTL_HTTP используется для связи с устройствами. В настоящее время устройства переключаются последовательно. После того, как все были переключены, пользователю отправляется электронное письмо. В зависимости от того, сколько устройств выбрано, выполнение этого последовательно может занять слишком много времени. Поэтому я смотрю на использование DBMS_SCHEDULER для выполнения переключения параллельно.

проблема в том, что процесс переключения возвращает статус, либо "ОК", либо причина его сбоя. Мне нужно, чтобы этот результат включался в электронное письмо пользователю. Итак, мне нужна "основная" процедура для создания заданий планировщика, а затем дождаться их завершения (и каким-то образом получить их статусы), прежде чем отправлять электронное письмо пользователю.

возможно ли это, если каждое задание не записывает его статус в таблицу, которая опрашивается "главный" процесс? Я читал ссылки на DBMS_PIPE для межпроцессной связи, но не нашел хорошего примера (т. е. того, который имеет смысл для меня), показывающий, как это сделать.

5 ответов


Если есть способ сделать это, я не мог понять. Я закончил тем, что каждая работа записывала ее статус в таблицу. Основной процесс знает, сколько отдельных заданий было создано, и опрашивает таблицу, чтобы сообщить, когда все задания завершены (или тайм-аут после определенного количества времени, в случае, если одно из заданий умирает по какой-либо причине).


альтернативное решение для просмотра параллельных процессов, выполняемых через задания DBMS_SCHEDULER

новое редактирование: сокращенное Обсуждение основной проблемы

(Edit: 03/10/2014) я добавил Это обсуждение после некоторых полезных отзывов от одного из плакатов, смотрящих эту тему.

Открыть Комментарии: другие темы обсуждения здесь упоминают использование некоторого выходного значения из самого вызова функции. Это не нативно возможно с существующим DBMS_SCHEDULER функции.

нет OUT значения параметров типа или выходы функций, связанные с уведомлением условия, с которым столкнулась вызываемая процедура. Самая непосредственная проблема:как мы запускаем ряд связанных задач с помощью хранимой процедуры PL/SQL параллельно? (т. е., не дожидаясь друг друга, чтобы закончить перед каждым пуском себя.)

что касается процедуры задачи не ждите вывода состояния. Время отклика, вероятно, будет широко варьироваться, и все, что вызывает процедуру таким образом, также зависнет. Связанные процессы будут ожидать завершения процедуры или возврата указанного вывода.

Предлагаемый Подход: другие комментарии по этой проблеме находятся на правильном пути. Имейте пользовательский вывод, записанный в таблицу, где его можно запросить позже, когда ответ будет готов. Если вы действительно хотите сделать это задачей hands-off, попробуйте поставить триггер на выходную таблицу. Каждый раз, когда заполняется сообщение определенного значения (представляющее завершенное состояние запроса), вызовите процедуру с почтовым пакетом Oracle, который отправляет ваше уведомление по электронной почте.

как отслеживать вызываемые задания, понимая DBMS_SCHEDULER особенности

использование запланированного задания является хорошим способом инициирования и просмотра набора вызовов процедур, которые не являются последовательно зависимые друг от друга. Я смог выполнить аналогичный подход, используя оригинальный DBMS_JOB функциональность предыдущих версий базы данных Oracle.

Пример: используя веб-интерфейс приложения (Oracle Application Express) у меня был проект, который позволил пользователю инициировать ресурсоемкую серию операций с базой данных. Инициировать запрос-это все, что было нужно.

Фактический Сценарий Использования: пользователю не нужно ждать его завершения. Проблема заключалась в том, что подключение формы веб-запроса непосредственно к вызову этого пакета базы данных и его процедур также связывало контроль над формой и ее сеансом, заставляя пользователя "ждать" завершения самой процедуры.

запуск запланированного задания, вызвавшего этот процесс, отделил взаимодействие с веб-страницей от ожидания фактического процесса завершать. Планирование задания было почти мгновенным, поэтому ожидание между отправкой запроса и возвращением контроля на веб-страницу Также было незначительным.

использование Oracle DBMS_SCHEDULER: введение в подход

текущая проблема и обсуждаемое решение: используйте уроженца DBMS_SCHEDULER представления состояния для мониторинга хода процесса. Их много, но ALL_SCHEDULER_JOB_LOG является более простым из коллекции и является хорошим началом того, что мы пытаемся достичь.

  1. использовать легко идентифицируемое имя для каждого задания... а также каждая работа, которая может быть связана друг с другом.
  2. инициировать дополнительное задание смотреть все параллельные задачи до последнего завершения. Измените эту" наблюдающую " работу, чтобы закончить, как только это условие будет выполнено.

основной синтаксис для инициирования Задание базы данных на планировщике

процедура DBMS_SCHEDULER.CREATE_JOB создает задание за один вызов без использования существующей программы или расписания:

DBMS_SCHEDULER.CREATE_JOB (
   job_name             IN VARCHAR2,
   job_type             IN VARCHAR2,
   job_action           IN VARCHAR2,
   number_of_arguments  IN PLS_INTEGER              DEFAULT 0,
   start_date           IN TIMESTAMP WITH TIME ZONE DEFAULT NULL,
   repeat_interval      IN VARCHAR2                 DEFAULT NULL,
   end_date             IN TIMESTAMP WITH TIME ZONE DEFAULT NULL,
   job_class            IN VARCHAR2                 DEFAULT 'DEFAULT_JOB_CLASS',
   enabled              IN BOOLEAN                  DEFAULT FALSE,
   auto_drop            IN BOOLEAN                  DEFAULT TRUE,
   comments             IN VARCHAR2                 DEFAULT NULL);

это входные параметры, на которые следует обратить пристальное внимание:

  • имя_задания вы можете оставить его по умолчанию, или вы можете помочь организовать ваши запросы работа через последовательную соглашение об именах. JOB_NAME-это специальный параметр, поскольку он имеет вспомогательную функцию с именем *GENERATE_JOB_NAME*, где можно указать префикс именования для объединения с внутренним назначением имени. В этом нет необходимости, но это помогает.

    DBMS_SCHEDULER.GENERATE_JOB_NAME 
        (prefix IN VARCHAR2 DEFAULT 'JOB$_') RETURN VARCHAR2;
    

    пример вызова в определении create_job:

    job_name => dbms_scheduler.generate_job_name( prefix => 'MY_EXAMPLE_JOB_')
    

    таким образом, в приведенном выше примере мы могли бы иметь ряд заданий с такими именами, как: MY_EXAMPLE_JOB_0001, MY_EXAMPLE_JOB_0002, MY_EXAMPLE_JOB_0003...

  • job_type это прямо из документации Oracle. Скорее всего, это будет тип: * plsql_block* (значение также может быть чувствительным к регистру).

  • repeat_interval не устанавливайте это значение для одноразовых параллельных задач. Задание будет идентифицироваться как завершенное, как только указанная хранимая процедура завершится или возникнут ошибки из.

  • конечная_дата оставьте это значение null или неназначенным. Это значение не применяется для одноразового выполнения наблюдаемой процедуры.

  • начальная_дата оставьте это значение null или неназначенным. Нет значения означает инициировать указанное задание, как только задание включено.

  • включено по умолчанию FALSE вам нужно будет указать правда как только вы создадите задание, или когда вы будете готовы начать процесс "поток".

  • auto_drop это важный вопрос. Остальная часть этого метода зависит от метаданных каждого задания, оставшихся в таблицах журнала DBMS_SCHEDULER, даже после того, как они попали в исключение или достигли завершения. Установите FALSE.

  • job_action это будет зависеть от количества параллельных процессов, которые вы инициируете. Во-первых, вы должны инициировать первый из ваших параллельных процессов... а также связанный с этим процесс" мониторинга", который будет активен для конкретного запроса. Действия задания на plsql_block тип задания выглядит примерно так:

    пример блока PL / SQL: BEGIN my_procedure (a, b, c); END;

создание процесса мониторинга заданий

часть проблемы, с которой вы столкнулись, заключается в том, что DBMS_SCHEDULER может наблюдать процесс изменения времени выполнения, но не очень хорошо сообщать вам, когда это сделано или если оно столкнулось с исключением.

ваш процесс "наблюдатель" просто должен быть другим запланированным заданием, которое запрашивает ALL_SCHEDULER_JOB_LOG таблица для процедур, за которые она отвечает, и выясняет, достигли ли все они желаемого статуса закрытия.

предположение: для данного запроса вы будете знать количество параллельных процессов (удаленно инициированных событий переключения), необходимых для выполнения этого типа запроса... все процессы не должны запускаться точно в то же время, но наблюдатель должен знать, что он все еще должен ждать, даже если все связанные процессы, которые он может видеть, соответствуют его критериям как "завершенный."

виды задач, которые ваша процедура" просмотра " должна будет включать:

WATCHING SQL Criteria Example:

WITH   MONITOR_QUERY AS (
       SELECT COUNT(LOG_ID) AS COMPLETED_PROCESS_COUNT
         FROM ALL_SCHEDULER_JOB_LOG
        WHERE JOB_NAME LIKE '001-REQUEST%')

SELECT CASE WHEN COMPLETED_PROCESS_COUNT = <TOTAL_PROCESSES>
            THEN 'DONE' ELSE 'IN-PROGRESS' END as REQUEST_STATUS
  FROM MONITOR_QUERY

также обратите внимание, что при вызове задания, которое запускает процесс мониторинга, вы можете сгенерировать уникальное имя задания раньше времени, прежде чем начать его повторяющееся задание (должно быть сделано только один раз за запрос или набор параллельных заданий):

DECLARE
   who_am_i   VARCHAR2(65);

BEGIN
   SELECT dbms_scheduler.generate_job_name
     INTO who_am_i
     FROM DUAL;

   --
   DBMS_SCHEDULER.CREATE_JOB (job_name => who_am_i,
     job_type => 'plsql_block',
     job_action => 'BEGIN my_monitoring_task(p_1, p_2, who_am_i); END',
     repeat_interval => 300,
     comments => 'Interval time units are defaulted to SECONDS';
     ...);

END;

это задание наиболее эффективно, если оно создано одновременно или вскоре после первого параллельно запускается работа в серии.

когда отслеживаемый запрос будет завершен

когда критерии выбора выполнены (т. е. все связанные процессы каким-то образом закрыты), тогда пришло время запустить ваше уведомление, а также остановить наблюдателя для этого запроса.

Stopping the Monitoring Job

DBMS_SCHEDULER.STOP_JOB (
   job_name         IN VARCHAR2
   force            IN BOOLEAN DEFAULT FALSE);    
  • имя_задания если вы использовали пользовательскую схему именования для каждого инициируемого задания, вы также можете сохранить это значение в качестве входного параметра в ваш вызов процедуры наблюдателя. Наблюдатель будет знать, как отключить себя, когда это будет сделано. Помните, что если вы используете вызов функции GENERATE_JOB_NAME, вы указываете только префикс для всего job_name, используемого в планировщике.

  • силу установите это значение FALSE (по умолчанию) или оставить его незаданным. Лучше позволить Oracle найти способ изящно поставить свою работу наблюдателя на стой.

Заключительные мысли и комментарии

если результат или завершение нескольких ваших процедур связаны, дополнительное запланированное задание может быть повторено как мониторинг "сердцебиения", чтобы проверить, выполнены ли все зависимости для дискретного процесса.

комментарий к очистке: этот дизайн требует, чтобы параметр * auto_drop * был установлен как FALSE. Ежедневный или еженедельный процесс также может быть запланирован для выпуска *drop_job* команда, которая очистит журналы планировщика записей, связанных с завершенными и сообщенными запросами.

вы также можете увидеть, включив вызов *job_name* в самом запланированном задании, вы можете предоставить процедуру(ы), содержащуюся в нем, возможность отключить себя, как только будут выполнены правильные условия.


расширенные очереди на спасение. Подчиненные сеансы (задания), когда они готовы, помещают свои возвращаемые значения в AQ (практически любая структура данных разрешена). Сеанс координатора, который инициировал подчиненные устройства, прослушивает очередь и собирает возвращаемые значения. На самом деле, AQs-рекомендуемый способ межсекционной связи в Oracle в любом случае.


в Oracle 12c столбец ALL_SCHEDULER_JOB_RUN_DETAILS.Вывод может использоваться для возврата значений из задания.

например, создайте задание и напишите вывод с помощью DBMS_OUTPUT:

begin
    dbms_scheduler.create_job(
        job_name => 'TEST_JOB',
        job_type => 'PLSQL_BLOCK',
        job_action => q'[begin dbms_output.put_line('Test output'); end; ]',
        enabled => true
    );
end;
/

теперь читаем вывод:

select job_name, to_char(log_date, 'YYYY-MM-DD') log_date, output
from all_scheduler_job_run_details
where owner  = user
    and job_name = 'TEST_JOB'
order by log_date desc;

JOB_NAME   LOG_DATE     OUTPUT
--------   --------     -------
TEST_JOB   2017-12-26   Test output

Если вы можете использовать oracle версии 11, вы можете использовать пакет DBMS_PARALLEL_EXECUTE pl/sql, который делает то, что вы хотите. Если вы не можете обновить, вы можете реализовать некоторые выноски c из pl / sql, которые обеспечивают аналогичную функциональность.

Если вы решили использовать dbms_pipe и используете параметр базы данных RAC, имейте в виду, что использование DBMS_PIPE имеет свои ограничения для отработки отказа.