I m trying to crate notification to send email whenever job is broken. This is the job:
declare
jobno number;
begin
dbms_job.submit( jobno,
'test_job_procedure;',
SYSDATE,
'SYSDATE + 1/24 /12');
commit;
end;
This is configuration of credentials :
BEGIN
DBMS_SCHEDULER.create_credential (credential_name => 'MAILSERVER_CREDENTIAL',
username => 'test#gmail.com',
password => 'test');
END;
BEGIN
DBMS_SCHEDULER.set_scheduler_attribute ('email_server', 'smtp.gmail.com:587');
DBMS_SCHEDULER.set_scheduler_attribute ('email_sender', 'test#gmail.com');
DBMS_SCHEDULER.set_scheduler_attribute ('email_server_credential', 'MAILSERVER_CRED
ENTIAL');
END;
And this is email notification scheduler: Instead of what there was job_name but in dbms_job job names are numbers which are non consistent, when I restart the job it gets new number so I put WHAT as something that will recognize that job. I don't know if this could work because I am getting error at the end but anyway when i run this select
SELECT *
FROM all_scheduler_global_attribute
I get this results https://imgur.com/a/FnQJ7
And this is job email notification :
BEGIN
DBMS_SCHEDULER.ADD_JOB_EMAIL_NOTIFICATION (
what => 'test_job_procedure',
recipients => 'test1#gmail.com',
sender => 'test#gmail.com',
subject => 'Scheduler Job Notification',
body => '%event_type% occurred at %event_timestamp%. %error_message%',
events => 'JOB_FAILED, JOB_BROKEN');
END;
can someone please go through this and tell me where am I making mistakes ?
Related
I have scheduled a PL/SQL procedure. I want to send the status of the PL/SQL procedure (whether it is successful or has any error messages) to my email address.
I saw some ways of sending pre-defined templates of emails using UTL_MAIL. But how can I get the status of my procedure into an email?
Send an e-mail at the end of the scheduled stored procedure, e.g.
create or replace procedure p_your_proc as
l_error varchar2(300);
begin
-- do some processing
-- if there were no errors
utl_mail.send(sender => 'rosh#gmail.com',
recipients => 'rosh#gmail.com',
cc => null,
bcc => null,
subject => 'Procedure P_YOUR_PROC completed successfully',
message => null);
exception
when others then
l_error := sqlerrm;
utl_mail.send(sender => 'rosh#gmail.com',
recipients => 'rosh#gmail.com',
cc => null,
bcc => null,
subject => 'Procedure P_YOUR_PROC ended with an error',
message => l_error);
raise;
end;
Is there a way how can i get all the users recently connected to particular database along with their Host Name . I want to trigger this Sql or procedure in a form of job and schedule the job in oracle to run in every one hour.
Please suggest with any options.
The below PL/SQL block creates a job that looks at the audit trail, creates a list of users and hosts that have logged on in the past hour, and emails the results.
Before the code can work, you may have to install UTL_MAIL:
sqlplus sys/<pwd>
SQL> #$ORACLE_HOME/rdbms/admin/utlmail.sql
SQL> #$ORACLE_HOME/rdbms/admin/prvtmail.plb
You may also need to set the parameter SMTP_OUT_SERVER, and possibly configure an ACL in the database to give you permission to send emails. Just follow the error messages and use Google to fix them.
If your database is not already auditing connections, run:
audit connect;
Finally, create the job like below. This is a very simple, text formatted email using DBMS_SCHEDULER, DBA_AUDIT_TRAIL, and UTL_MAIL.
--Create an hourly job to email the last hours worth of logons.
begin
dbms_scheduler.create_job(
job_name => 'hourly_logons',
job_type => 'plsql_block',
start_date => systimestamp at time zone 'US/Eastern',
repeat_interval => 'freq=hourly;byminute=0;',
enabled => true,
job_action =>
q'[
declare
v_message varchar2(32767);
begin
--Create the message based on audit entries.
for rows in
(
select username, userhost, count(*) the_count
from dba_audit_trail
where timestamp > systimestamp - interval '1' hour
and action_name = 'LOGON'
group by username, userhost
order by 1,2
) loop
v_message := v_message || rows.username || chr(9) || rows.userhost || chr(9) ||
rows.the_count || chr(10);
end loop;
--Email the message
utl_mail.send
(
sender => 'some_address#some_domain.com',
recipients => 'some_address#some_domain.com',
subject => 'Logons in past hour',
message => v_message
);
end;
]'
);
end;
/
You may want to manually run the job during testing, and check the scheduler metadata:
--Force the job to run:
begin
dbms_scheduler.run_job('HOURLY_LOGONS');
end;
/
--Check the job status and history.
select * from dba_scheduler_jobs where job_name = 'HOURLY_LOGONS';
select * from dba_scheduler_job_run_details where job_name = 'HOURLY_LOGONS' order by log_date desc;
The above code is not tested because I don't have a mail server setup on my home machine. But I've done this several times before and am certain that something very close to this should work.
I have an apex application where i need to send a notification mail to all the employees on the 5th of every month. So just for the sake of testing i am trying to send a mail in every 30 seconds. I created a job scheduler on a procedure to do the same. Here is the PLSQL code for it.
create or replace procedure send_notification_employee as
cursor c_employee is select * from EMPLOYEE;
r_employee c_employee%ROWTYPE;
begin
open c_employee;
loop
fetch c_employee into r_employee;
exit when c_employee%NOTFOUND;
APEX_MAIL.SEND(
p_to => r_employee.EMPLOYEE_EMAIL,
p_from => 'abc#gmail.com',
p_subj => 'Reminder : Meeting',
p_body => '<Some random message>');
end loop;
close c_employee;
end;
/
begin
DBMS_SCHEDULER.CREATE_JOB(
job_name => 'send_notification',
job_type => 'stored_procedure',
job_action => 'send_notification_employee',
start_date => NULL,
repeat_interval => 'FREQ=SECONDLY;INTERVAL=30',
end_date => NULL);
end;
/
begin
DBMS_SCHEDULER.enable(
name => 'send_notification');
end;
/
I guess the code is correct. The only thing i am not sure of is to how to run this scheduler on the apex oracle application. Should i just execute these statements on the SQL Commands or is there any other way to do it?
Also i tried to execute the same statements in the SQL Commands tab but i don't receive any mails as such. Is there any issue with my code? Thanks in advance.
You need to set the security group if sending the mail from the database rather than from APEX directly. You should also use push_queue at the end of the procedure to clear out the table of unsent mail.
create or replace procedure send_notification_employee as
cursor c_employee is select * from EMPLOYEE;
r_employee c_employee%ROWTYPE;
l_workspace number;
begin
-- Get a valid workspace ID
SELECT MAX(workspace_id) INTO l_workspace FROM apex_applications WHERE application_id = <valid application_id>;
-- Set Workspace
wwv_flow_api.set_security_group_id(l_workspace);
open c_employee;
loop
fetch c_employee into r_employee;
exit when c_employee%NOTFOUND;
APEX_MAIL.SEND(
p_to => r_employee.EMPLOYEE_EMAIL,
p_from => 'abc#gmail.com',
p_subj => 'Reminder : Meeting',
p_body => '<Some random message>');
end loop;
close c_employee;
-- Finally force send
APEX_MAIL.PUSH_QUEUE;
end;
Re. how to execute - it depends on what you want to do. If you just want to run it on the 5th of every month just setup a scheduled job in the db to do it, as you have above. If you want to run on an adhoc basis just create a job in an APEX after submit process that calls the procedure and executes through the database.
As an aside, if you plan to create many mail procedures you may wish to create a helper procedure to get the workspace id / send the mail, and just call it from your other mail procedures.
These queries could be handy (To check if you have the correct set up):
Check if util_smtp is installed:
select * from dba_objects where object_name like 'UTL_SMTP%'
Check privileges:
select grantee , table_name , privilege from dba_tab_privs where table_name = 'UTL_SMTP'
Check open network hosts, ports:
select acl , host , lower_port , upper_port from DBA_NETWORK_ACLS;
Check network privileges:
select acl , principal , privilege , is_grant from DBA_NETWORK_ACL_PRIVILEGES
I'm currently trying to implement a similar version of oracle's APEX_MAIL package. I have everything working, but I can't make the job work unless I modify it.
The job APEX_MAIL uses is called ORACLE_APEX_MAIL_QUEUE
BEGIN
DBMS_SCHEDULER.set_attribute( name => '"APEX_040000"."ORACLE_APEX_MAIL_QUEUE"', attribute => 'job_action', value => 'APEX_040000.WWV_FLOW_MAIL.PUSH_QUEUE');
DBMS_SCHEDULER.set_attribute( name => '"APEX_040000"."ORACLE_APEX_MAIL_QUEUE"', attribute => 'number_of_arguments', value => '2');
DBMS_SCHEDULER.SET_JOB_ARGUMENT_VALUE(
job_name => '"APEX_040000"."ORACLE_APEX_MAIL_QUEUE"',
argument_position => 1,
argument_value => '');
DBMS_SCHEDULER.SET_JOB_ARGUMENT_VALUE(
job_name => '"APEX_040000"."ORACLE_APEX_MAIL_QUEUE"',
argument_position => 2,
argument_value => '');
END;
/
So I go to the package to see what the code does. I'm was assuming push queue would send out emails in the queue. Instead, it calls the same job again!
PROCEDURE PUSH_QUEUE( P_SMTP_HOSTNAME IN VARCHAR2 DEFAULT NULL,
P_SMTP_PORTNO IN VARCHAR2 DEFAULT NULL )
IS
BEGIN
PUSH_QUEUE_BACKGROUND;
END PUSH_QUEUE;
PROCEDURE PUSH_QUEUE_BACKGROUND
IS
BEGIN
SYS.DBMS_SCHEDULER.RUN_JOB( JOB_NAME => 'ORACLE_APEX_MAIL_QUEUE', USE_CURRENT_SESSION => FALSE );
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE <> -27478 THEN
RAISE;
END IF;
END PUSH_QUEUE_BACKGROUND;
So basically this job does nothing, but I switch it to call PUSH_QUEUE_IMMEDIATE which does what I think it should do.
PROCEDURE PUSH_QUEUE_IMMEDIATE( P_FORCE_YN IN VARCHAR2 DEFAULT 'N')
IS
L_STATUS NUMBER;
L_LOCK_HDL VARCHAR2(128);
E_DB_SHUTDOWN EXCEPTION;
PRAGMA EXCEPTION_INIT(E_DB_SHUTDOWN, -1089);
BEGIN
WWV_FLOW_DEBUG.ENABLE_DBMS_OUTPUT;
SYS.DBMS_LOCK.ALLOCATE_UNIQUE( LOCKNAME => 'APEX_MAIL_QUEUE_LOCK', LOCKHANDLE => L_LOCK_HDL);
L_STATUS := SYS.DBMS_LOCK.REQUEST( LOCKHANDLE => L_LOCK_HDL,
LOCKMODE => SYS.DBMS_LOCK.X_MODE,
TIMEOUT => 0,
RELEASE_ON_COMMIT => FALSE );
WWV_FLOW_DEBUG.INFO('APEX Mail Lock status: ' || L_STATUS );
IF L_STATUS = 0 THEN
FOR C1 IN ( SELECT ID, MAIL_SEND_COUNT, LAST_UPDATED_ON
FROM WWV_FLOW_MAIL_QUEUE
ORDER BY MAIL_SEND_COUNT, LAST_UPDATED_ON) LOOP
BEGIN
WWV_FLOW_DEBUG.INFO( 'Pushing email: ' || C1.ID );
IF (C1.MAIL_SEND_COUNT = 0) OR (NVL(P_FORCE_YN,'N') = 'Y') OR
(C1.MAIL_SEND_COUNT > 0 AND (POWER(2,C1.MAIL_SEND_COUNT)/(60*24) + C1.LAST_UPDATED_ON) < SYSDATE) THEN
BACKGROUND( P_ID => C1.ID );
END IF;
WWV_FLOW_DEBUG.INFO( 'Pushed email: ' || C1.ID );
EXCEPTION
WHEN OTHERS THEN
WWV_FLOW_DEBUG.LOG_EXCEPTION;
IF L_LOCK_HDL IS NOT NULL THEN
L_STATUS := SYS.DBMS_LOCK.RELEASE( L_LOCK_HDL );
WWV_FLOW_DEBUG.INFO('APEX Mail released lock' );
END IF;
END;
END LOOP;
END IF;
IF L_LOCK_HDL IS NOT NULL THEN
L_STATUS := SYS.DBMS_LOCK.RELEASE( L_LOCK_HDL );
WWV_FLOW_DEBUG.INFO('APEX Mail released lock' );
END IF;
EXCEPTION WHEN E_DB_SHUTDOWN THEN
NULL;
END PUSH_QUEUE_IMMEDIATE;
I'm trying to copy APEX_MAIL to a point, but if I do, I won't have a working job. Can anyone point out if APEX_MAIL changes what the job does after an application setting change or any other change?
Thanks in advance!
APEX_MAIL.PUSH_QUEUE is usable in your own code to send your mail (in the queue) out immediate. The job normally calls PUSH_QUEUE_IMMEDIATE. I don't know if your setting ever was a bug in the installation or something wrong on your site.
Thus fact, it calls PUSH_QUEUE_IMMEDIATE in a separate session as APEX_040000 job.
Since everyone can request an immediate send of all the jobs in the queue, it makes sure via SYS.DBMS_LOCK.REQUEST only one session will actually do the transmit.
I'm loosing my mind. I have a procedure named foo() which takes no arguments. I'd like to execute it, let's say, every 3 minutes. The code I wrote looks like:
BEGIN
dbms_scheduler.create_job(job_name => FooJob,
job_type => 'PLSQL_BLOCK',
job_action => '
BEGIN
foo();
END;',
start_date => SYSTIMESTAMP,
repeat_interval => 'FREQ=MINUTELY;INTERVAL=3;BYHOUR=17;BYMINUTE=35;',
enabled => TRUE
comments => 'A comment.');
END;
/
This gives me an error: identificator 'applyjobpenalities' should be defined.
I based on this example: How to execute a procedure with DBMS_SCHEDULER.CREATE_JOB procedure
Also:
1) How to execute dbms_output.put_line() after execution of foo();? Is it possible to just put this line strightly away?
2) How to check if procedure foo() is (was) executing on behalf of scheduler?
UPDATE:
Ok so what I've done is:
1) I typed in SQL Plus 'set serveroutput on'
2) I made a procedure:
create or replace procedure proc1
IS
BEGIN
dbms_output.put_line('sth');
end;
/
3) I changed scheduler code to:
BEGIN
dbms_scheduler.create_job( job_name => 'JustATest',
job_type => 'PLSQL_BLOCK',
job_action =>
'BEGIN
proc1();
END;',
start_date => systimestamp + interval '10' second,
repeat_interval => 'FREQ=SECONDLY',
enabled => TRUE);
END;
/
But I can't see any result in SQL Plus. What am I missing? Both procedures compiled succesfully and I can see this job when I type:
SELECT * FROM DBA_SCHEDULER_JOBS;
1) There is no way to extract DBMS_OUTPUT from a scheduled job.
2) To check if FOO was executing, I use the following SQL (extracted from TOAD's "Spool SQL to Screen" option. If you are going to be spending any time at all developing in Oracle, get TOAD for Oracle).
SELECT l.job_name
, l.JOB_SUBNAME
, l.log_id "Log ID"
, l.log_date "Log Date"
, l.operation "Operation"
, l.status "Status"
, l.user_name "User Name"
, l.client_id "Client ID"
, l.global_uid "Global UID"
, r.req_start_date "Required Start Date"
, r.actual_start_date "Actual Start Date"
, r.run_duration "Run Duration"
, r.instance_id "Instance ID"
, r.session_id "Session ID"
, r.slave_pid "Slave PID"
, TO_CHAR (r.cpu_used) "CPU Used"
, r.additional_info "Additional Info (Run)"
FROM dba_scheduler_job_log l, dba_scheduler_job_run_details r
WHERE l.log_id = r.log_id(+)
and l.job_name like 'FooJob'
ORDER BY 1 DESC NULLS LAST;
2b) To see jobs that are currently running:
SELECT *
FROM dba_scheduler_running_jobs;
3) If you want to see results from your job, you need to have your job do something, such as insert a record into a table.
Change Job_action => 'proc1';
And in another notepad type
BEGIN
DBMS_SCHEDULER.RUN_JOB(
JOB_NAME => 'justATest',
USE_CURRENT_SESSION => FALSE);
END;
And then execute the above code
You can see result of dbms_output.put_line() in dba_scheduler_job_run_details column "output".
Put in job action
BEGIN
foo();
dbms_output.put_line( 'foo executed in job' ) ;
END;