我可以从dbms_scheduler作业以某种方式获得返回值吗?

时间:2014-01-21 20:31:32

标签: oracle plsql parallel-processing oracle10g

我有一个网页(通过PL / SQL生成),允许有人打开或关闭远程设备。它们会显示一个设备列表,并使用复选框选择要切换的设备。 UTL_HTTP用于与设备通信。目前,这些设备是连续切换的。切换完所有内容后,会向用户发送一封电子邮件。根据选择的设备数量,连续执行此操作可能需要很长时间。所以我正在考虑使用DBMS_SCHEDULER来并行执行切换。

问题是切换过程会返回状态,“确定”或失败的原因。我需要将结果包含在用户的电子邮件中。因此,我需要'main'程序来创建SCHEDULER作业,然后在向用户发送电子邮件之前等待它们完成(并以某种方式获取其状态)。

这是否可能,没有让每个工作将其状态写入由“主”流程轮询的表格?我已经阅读了DBMS_PIPE对进程间通信的引用,但是没有找到一个很好的例子(即对我有意义的一个)来展示如何做到这一点。

5 个答案:

答案 0 :(得分:1)

如果有办法,我无法理解。我最终让每个工作都将它的状态写入表格。主进程知道创建了多少个别作业,并轮询表以告知所有作业何时完成(或者在指定的时间过后超时,以防其中一个作业因某种原因而死亡)。

答案 1 :(得分:1)

通过DBMS_SCHEDULER作业运行的监视并行进程的备用解决方案

新编辑:核心问题的简短讨论

(编辑:03/10/2014)我在观看此主题的海报之一收到了一些有用的反馈后,我添加了这个讨论。

  

打开评论:这里的其他讨论话题提到了函数调用本身使用的一些输出值。使用现有的DBMS_SCHEDULER功能本身无法实现这一点。

     

没有OUT类型参数值或函数输出与通知调用的过程遇到的条件有关。手头上最直接的问题是:我们如何通过PL / SQL存储过程并行运行一系列相关任务?(即,在每次启动之前不等待彼此完成。)< / p>

无论调用过程任务,都不应该等待状态输出。响应时间可能会有很大的变化,无论以这种方式调用过程也会挂起。关联的进程将等待过程的完成或指定输出的返回。

  

建议的方法:关于此问题的其他评论是正确的。将自定义输出写入表中,以便在响应准备好后可以查询该表。如果你真的想让它成为一个不干涉的任务,试着在输出表上设置一个触发器。每次填充特定值的消息(表示请求的已完成状态)时,请使用发送通知电子邮件的Oracle邮件包调用一个过程。

如何通过了解DBMS_SCHEDULER功能

来跟踪您调用的作业

使用预定作业是启动和观看一组不依赖于彼此的过程调用的好方法。我已经能够使用以前版本的Oracle数据库的原始 DBMS_JOB 功能完成类似的方法。

  

案例研究:使用基于Web的应用程序界面(Oracle Application Express)我有一个项目允许用户启动资源密集型系列的数据库操作。只需要启动请求即可。

     

实际使用情景:用户无需等待其完成。问题是将Web请求表单直接连接到对此数据库包的调用,其程序还限制了对表单及其会话的控制,使用户等待&#34;程序本身就完成了。

关闭调用此过程的预定作业,将与网页的交互与等待实际过程完成分开。调度作业任务几乎是即时的,因此提交请求和将控制权返回到网页之间的等待时间也可以忽略不计。

使用Oracle DBMS_SCHEDULER:方法简介

正在讨论的当前问题和解决方案:使用原生 DBMS_SCHEDULER 状态视图来监控流程的进度。有许多,但 ALL_SCHEDULER_JOB_LOG 是收集的简单,是我们努力完成的一个良好的开端。

  1. 为每项工作使用易于识别的名称......以及每项可能彼此相关的工作。
  2. 启动其他作业以观察所有并行任务,直到最后一个完成。改变这一点&#34;观看&#34;一旦达到这个条件就结束工作。
  3. 在计划程序上启动数据库作业的基本语法

    程序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 您可以将其保留为默认值,也可以使用一致的命名约定来帮助组织作业请求。 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 不要为一次性并行任务设置此值。一旦引用的存储过程完成或错误输出,作业将标识为已完成。

    • end_date 保留此null或取消分配。该值不适用于一次性执行正在观察的程序。

    • start_date 保留此null或取消分配。没有值意味着只要作业 ENABLED 就启动指定的作业。

    • 已启用默认为 FALSE ,您需要在创建作业时立即将此设置为 TRUE ,或者当您& #39;准​​备启动流程&#34;线程&#34;。

    • auto_drop 这是一个重要的问题。此方法的其余部分取决于DBMS_SCHEDULER日志表中剩余的每个作业的元数据,即使它们遇到异常或已完成。将其设置为 FALSE

    • job_action 这取决于您启动的并行进程数。首先,您应该启动第一个并行流程......以及相关的&#34;监控&#34;对特定请求有效的进程。 plsql_block 类型作业的作业操作如下所示:

      示例PL / SQL块: BEGIN my_procedure(a,b,c);结束;

    创建工作监控流程

    您遇到的部分问题是DBMS_SCHEDULER可能会看到一个不同执行时间的过程,但它不是很擅长让您知道它何时完成或是否遇到异常。

    你的观察者&#34;进程只需要是另一个预定作业,查询ALL_SCHEDULER_JOB_LOG表中它负责的程序,并确定它们是否都已达到所需的结束状态。

      

    假设:对于给定的请求,您将知道完成此类请求所需的并行进程数(远程启动的切换事件)...所有进程不必完全同时启动,而是观察者需要知道它仍然必须等待,即使它可以看到的所有相关过程都符合其标准,并且#34;已完成&#34;。

    您观看的任务类型&#34;程序将需要包括:

    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);    
    
    • job_name 如果您为启动的每个作业使用了自定义命名方案,则还可以将此值作为输入参数存储到您的观察程序过程调用中。然后观察者会知道如何在完成后关闭自己。请记住,如果使用GENERATE_JOB_NAME函数调用,则只指定调度程序中使用的整个job_name的前缀。

    • 强制将此项设置为 FALSE (默认值)或保留未指定。最好让Oracle找到一种方法来优雅地让你的观察者工作停止。

    结束思考和评论

    如果您的几个程序的结果或完成相关,则可以重复另外的预定作业作为监控&#34;心跳&#34;检查是否已满足离散流程的所有依赖关系。

      

    关于清理的注释:此设计要求* auto_drop *参数设置为FALSE。还可以安排每日或每周进程发出* drop_job *命令,该命令将清除调度程序与已完成和已报告请求相关的记录日志。

    您还可以看到,通过在计划作业本身中包含调用* job_name *,您可以在其中包含的程序中提供在满足正确条件后自行关闭的程序。

答案 2 :(得分:0)

高级队列救援。 从属会话(作业)在准备就绪时将其返回值放入AQ(实际上允许任何数据结构)。 启动从站的协调器会话侦听队列并收集返回值。 实际上,无论如何,AQ是Oracle中闭会期间通信的推荐方式。

答案 3 :(得分:0)

在Oracle 12c中,列ALL_SCHEDULER_JOB_RUN_DETAILS.OUTPUT可用于从作业返回值。

例如,使用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

答案 4 :(得分:-1)

如果您能够使用oracle版本11,则可以使用DBMS_PARALLEL_EXECUTE pl / sql包,它可以执行您想要的操作。如果你无法升级,那么你可以从pl / sql实现一些提供类似功能的c标注。

如果您决定使用dbms_pipe并且您正在使用RAC数据库选项,请注意使用DBMS_PIPE具有故障转移的限制。

相关问题