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

问题描述 投票:6回答:5

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

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

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

oracle plsql parallel-processing oracle10g
5个回答
1
投票

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


1
投票

An Alternate Solution to Watching Parallel Processes Run Through DBMS_SCHEDULER Jobs

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

(编辑:03/10/2014)我在观看了这个帖子的一个海报的一些有用的反馈后添加了这个讨论。

打开注释:这里的其他讨论线程提到了函数调用本身的一些输出值的使用。现有的DBMS_SCHEDULER功能本身不可能实现这一点。

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

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

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

如何通过了解DBMS_SCHEDULER功能来跟踪您调用的作业

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

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

实际使用场景:用户无需等待其完成。问题是将Web请求表单直接连接到对此数据库包的调用,并且其过程还限制了对表单及其会话的控制,使得用户“等待”该过程本身完成。

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

使用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您可以将其保留为默认值,也可以使用一致的命名约定来帮助组织作业请求。 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或未分配。没有值意味着在作业启用后立即启动指定的作业。
  • 已启用默认为FALSE您需要在创建作业后立即将其设置为TRUE,或者您已准备好启动“线程”进程。
  • auto_drop这是一个重要的问题。此方法的其余部分取决于DBMS_SCHEDULER日志表中保留的每个作业的元数据,即使它们遇到异常或已完成。将此设置为FALSE。
  • job_action这取决于您启动的并行进程数。首先,您应该启动第一个并行流程...以及对特定请求有效的相关“监控”流程。 plsql_block类型作业的作业操作如下所示: 示例PL / SQL块:BEGIN my_procedure(a,b,c);结束;

创建工作监控流程

您遇到的部分问题是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);    
  • job_name如果为启动的每个作业使用自定义命名方案,则还可以将此值作为输入参数存储到watcher过程调用中。然后观察者会知道如何在完成后关闭自己。请记住,如果使用GENERATE_JOB_NAME函数调用,则只为调度程序中使用的整个job_name指定前缀。
  • force将此值设置为FALSE(默认值)或保留未指定值。最好让Oracle找到一种方法来优雅地让你的观察者工作停止。

结束思考和评论

如果几个过程的结果或完成相关,则可以重复另外的预定作业作为监视“心跳”,以检查是否已满足离散过程的所有依赖性。

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

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


0
投票

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


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

-1
投票

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

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

© www.soinside.com 2019 - 2024. All rights reserved.