If you keep a separate table to maintain whether your procedure is running or not, then you only need to keep a lock as long as it takes you to update the table to ensure that another session is not doing the same. Here is some code to setup the table and then use it to run your procedure.
--Setup
CREATE TABLE ProcedureLock AS (SELECT logon_time FROM v$session WHERE rownum<=1);
UPDATE ProcedureLock SET Logon_Time = NULL;
COMMIT;
--Use
DECLARE
vLogon_Time ProcedureLock.Logon_Time%Type;
eInUse Exception;
PRAGMA EXCEPTION_INIT (eInUse, -54);
BEGIN
Begin
SELECT Logon_Time INTO vLogon_Time FROM ProcedureLock FOR UPDATE NOWAIT;
Exception
When eInUse Then
DBMS_Output.Put_Line('The procedure is running.');
Return;
End;
UPDATE ProcedureLock SET Logon_Time =
(SELECT min(logon_time) FROM gv$session WHERE SID = SYS_CONTEXT('USERENV','SID'))
WHERE Logon_Time IS NULL;
If (SQL%ROWCOUNT <> 1) Then
DBMS_Output.Put_Line('The procedure is running or failed to complete.');
Return;
End If;
COMMIT;
DBMS_Output.Put_Line('The procedure is NOT running.');
DBMS_Output.Put_Line('Run Procedure here.');
UPDATE ProcedureLock SET Logon_Time = NULL;
COMMIT;
END;
/
First we lock the new ProcedureLock table and then update it. If either of these fail we know the procedure is running and therefore we should not run it again.