Skip to Main Content

Breadcrumb

Question and Answer

Tom Kyte

Thanks for the question, Patrick.

Asked: January 24, 2003 - 6:14 pm UTC

Last updated: January 28, 2004 - 8:47 am UTC

Version: 9.0.1

Viewed 1000+ times

You Asked

I have a PL/SQL (daemon) procedure that looks like this:

DBMS_ALERT.REGISTER(alert_name);
loop
select
update
insert
etc.

DBMS_ALERT.WAITANY(alert_name, msg, status, sleep_secs);
if status != 1 then
exit;
end if;
end loop

The purpose of this procedure is to periodically check a table for some things to do, do them, and then sleep until it has to do it again. While it is sleeping, a user can send an alert to the process and shut it down.

This all works just fine. The problem is that this procedure is always ACTIVE. This makes it difficult to shut down the database because "shutdown immediate" waits for ACTIVE processes to complete.

My question is, is there a way to "sleep" while in an INACTIVE state? The alternative is to provide the DBA with a script to assign to a database shutdown trigger that will send out the shutdown alert to this process, but I would rather not have to be dependent on this.


and Tom said...

shutdown immediate does not wait for actives?

shutdown normal does. Consider:

ops$tkyte@ORA920> exec dbms_alert.register( 'x' );
PL/SQL procedure successfully completed.

ops$tkyte@ORA920> variable n varchar2(25)
ops$tkyte@ORA920> variable m varchar2(255)
ops$tkyte@ORA920> variable s number
ops$tkyte@ORA920> exec dbms_alert.waitany( :n, :m, :s );

at this point, connected as sysdba in another window and did shutdown immediate. after a very short period of time:


ERROR:
ORA-01089: immediate shutdown in progress - no operations are permitted


BEGIN dbms_alert.waitany( :n, :m, :s ); END;

*
ERROR at line 1:
ORA-20000: ORU-10015: error:3 waiting for pipe message.
ORA-06512: at "SYS.DBMS_ALERT", line 148
ORA-06512: at "SYS.DBMS_ALERT", line 281
ORA-06512: at line 1


So, if shutdown immediate isn't shutting down immediately -- you have a different problem (eg: a long running transaction is being gently rolled back and you are just waiting on it)




that block of code, by definition, will be active always -- until it RETURNS from the database. The client running this block of code is the only thing that can make us go inactive.



Rating

  (2 ratings)

Is this answer out of date? If it is, please let us know via a Comment

Comments

I left out some important details

Patrick Mealey, January 26, 2003 - 12:29 am UTC

My DBA had told me about the ACTIVE session/shutdown immediate thing which got me off track. Your example got me back on track. The details I left out are significant to my problem. Consider this fragment:
set serveroutput on size 1000000
declare
alert_name VARCHAR2(30);
alert_msg VARCHAR2(1024);
alert_status NUMBER;
timeout NUMBER;
begin
alert_name := 'foo';
timeout := 30;
dbms_alert.register(alert_name);

loop

begin

--do various user defined actions here

dbms_alert.waitany(alert_name, alert_msg, alert_status, timeout);
if alert_status != 1 then
dbms_output.put_line('ending normally');
exit;
end if;
dbms_output.put_line('looping');
exception
when others then
--log the exception and keep going
dbms_output.put_line('ignoring exception');
end;

end loop;

exception
when others then
dbms_output.put_line(sqlerrm);
end;

The code ignores exceptions in the loop because it is performing various user defined SQL tasks which may throw exceptions. These exceptions cannot be fatal to the loop because this is supposed to be a daemon-like process. The unfortunate side effect is that it ignores the exception caught during database shutdown which then causes a shutdown hang.
I will move the exception handler above the DBMS_ALERT.WAIT line to let any excpetions thrown during the WAIT get handled.

Tom Kyte
January 26, 2003 - 9:15 am UTC

Your code should be:


set serveroutput on size 1000000
declare
alert_name VARCHAR2(30) := 'foo';
alert_msg VARCHAR2(1024);
alert_status NUMBER;
timeout NUMBER := 30;
begin
dbms_alert.register(alert_name);
loop
begin
BEGIN
--do various user defined actions here
exception when others then
--log the exception and keep going
dbms_output.put_line('ignoring exception');
END;

dbms_alert.waitany(alert_name, alert_msg, alert_status, timeout);
exit when ( alert_status != 1 );
end loop;
end;


Your code goes into an infinite loop if the user defined action flings an exception time after time even in the BEST of situations. you had:

loop
user code

dbms_alert code
end loop

if user code flung an exception, you would goto the bottom of the code and do user code all over again. having dbms_output in there is not really useful as no one will ever see it.

A reader, January 28, 2004 - 8:47 am UTC


More to Explore

PL/SQL demos

Check out more PL/SQL tutorials on our LiveSQL tool.

PL/SQL docs

PL/SQL reference manual from the Oracle documentation library