我有一个网页(通过PL / SQL生成),允许有人打开或关闭远程设备。它们会显示一个设备列表,并使用复选框选择要切换的设备。 UTL_HTTP用于与设备通信。目前,这些设备是连续切换的。切换完所有内容后,会向用户发送一封电子邮件。根据选择的设备数量,连续执行此操作可能需要很长时间。所以我正在考虑使用DBMS_SCHEDULER来并行执行切换。
问题是切换过程返回状态,“确定”或失败的原因。我需要将结果包含在用户的电子邮件中。因此,我需要'main'程序来创建SCHEDULER作业,然后在向用户发送电子邮件之前等待它们完成(并以某种方式获取其状态)。
这是否可能,没有让每个工作将其状态写入由“主”流程轮询的表格?我已经阅读了DBMS_PIPE对进程间通信的引用,但是没有找到一个很好的例子(即对我有意义的一个)来展示如何做到这一点。
如果有办法做到这一点,我无法理解。我最终让每个工作都将它的状态写入表格。主进程知道创建了多少个别作业,并轮询表以告知所有作业何时完成(或者在指定的时间过后超时,以防其中一个作业因某种原因而死亡)。
(编辑:03/10/2014)我在观看了这个帖子的一个海报的一些有用的反馈后添加了这个讨论。
打开注释:这里的其他讨论线程提到了函数调用本身的一些输出值的使用。现有的
DBMS_SCHEDULER
功能本身不可能实现这一点。没有与通知调用的过程遇到的条件相关的
OUT
类型参数值或函数输出。目前最紧迫的问题是:我们如何通过PL / SQL存储过程并行运行一系列相关任务? (即,在每次开始之前,不要等待彼此完成。)
无论什么调用过程任务都不应该等待状态输出。响应时间可能会有很大的变化,无论以这种方式调用过程也会挂起。关联进程将等待过程完成或返回指定的输出。
建议的方法:关于这个问题的其他评论是正确的。将自定义输出写入表中,以便在响应准备好后可以查询该表。如果你真的想让它成为一个不干涉的任务,试着在输出表上设置一个触发器。每次填充特定值的消息(表示请求的完成状态)时,使用发送通知电子邮件的Oracle Mail包调用一个过程。
DBMS_SCHEDULER
功能来跟踪您调用的作业使用预定作业是启动和观看一组不依赖于彼此的过程调用的好方法。我已经能够使用以前版本的Oracle数据库的原始DBMS_JOB功能来完成类似的方法。
案例研究:使用基于Web的应用程序界面(Oracle Application Express)我有一个项目允许用户启动资源密集型系列的数据库操作。只需要启动请求即可。
实际使用场景:用户无需等待其完成。问题是将Web请求表单直接连接到对此数据库包的调用,并且其过程还限制了对表单及其会话的控制,使得用户“等待”该过程本身完成。
关闭调用此过程的预定作业将与网页的交互与等待实际过程完成分开。调度作业任务几乎是即时的,因此提交请求和将控制权返回到网页之间的等待时间也可以忽略不计。
讨论中的当前问题和解决方案:使用本机DBMS_SCHEDULER状态视图来监视进程的进度。有很多,但ALL_SCHEDULER_JOB_LOG是集合的简单,是我们想要完成的一个良好的开端。
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);
这些是你应该密切关注的输入参数:
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 ...您遇到的部分问题是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);
如果几个过程的结果或完成相关,则可以重复另外的预定作业作为监视“心跳”,以检查是否已满足离散过程的所有依赖性。
关于清理的注释:此设计要求将* auto_drop *参数设置为FALSE。还可以安排每日或每周进程发出* drop_job *命令,该命令将清除调度程序与已完成和已报告请求相关的记录日志。
您还可以通过在计划作业本身中包含调用* job_name *来查看,您可以提供其中包含的过程,以便在满足正确条件后自行关闭。
高级队列救援。从属会话(作业)在准备就绪时将其返回值放入AQ(实际上允许任何数据结构)。启动从站的协调器会话侦听队列并收集返回值。实际上,无论如何,AQ是Oracle中闭会期间通信的推荐方式。
在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
如果您能够使用oracle版本11,则可以使用DBMS_PARALLEL_EXECUTE pl / sql包,它可以执行您想要的操作。如果你无法升级,那么你可以从pl / sql实现一些提供类似功能的c标注。
如果您决定使用dbms_pipe并且使用RAC数据库选项,请注意使用DBMS_PIPE具有故障转移的限制。