0

我有一个发送电子邮件的程序,这个程序被其他函数和程序调用(主要用于发送警报和通知)。

我面临的一个问题是,如果我们的邮件服务器出现故障,那么调用函数或过程就会停止执行,我的意思是他们没有执行他们应该执行的任何功能。我如何确保调用函数或过程或任何调用 MailProcedure 的客户端即使在邮件服务器关闭时也应该执行其功能。

我怎样才能做到这一点?任何帮助都是非常可观的。

邮件程序

CREATE OR REPLACE PROCEDURE MailProcedure(frm_id IN VARCHAR2, to_id IN VARCHAR2, subject IN VARCHAR2, body_text IN VARCHAR2)
AS
c utl_tcp.connection;
rc integer;
BEGIN
 c := utl_tcp.open_connection('email_server', 25);  
 rc := utl_tcp.write_line(c, 'string'); 
 rc := utl_tcp.write_line(c, 'from address'); 
 rc := utl_tcp.write_line(c, 'to address');  
 rc := utl_tcp.write_line(c, 'Subject'); 
 rc := utl_tcp.write_line(c, 'body');  
 utl_tcp.close_connection(c); 
EXCEPTION
    WHEN OTHERS
    THEN
        null;
END;
/
4

1 回答 1

3

由于您希望将电子邮件排队以供以后发送,因此最简单的选择是异步发送所有电子邮件消息。您的其他过程将调用一个QueueMail将行插入新mail_queue表的过程

CREATE OR REPLACE PROCEDURE QueueMail(p_from IN VARCHAR2, 
                                      p_to IN VARCHAR2, 
                                      p_subject IN VARCHAR2, 
                                      p_body IN VARCHAR2)
AS
BEGIN
  INSERT INTO mail_queue( mail_queue_id. from, to, subject, body )
    VALUES( mail_queue_seq.nextval, p_from, p_to, p_subject, p_body );
END;

然后,您将有一个单独的过程在一个单独的线程中运行,该线程实际感测电子邮件并从队列中删除消息。就像是

CREATE OR REPLACE PROCEDURE SendQueuedMessages
AS
BEGIN
  FOR msg IN (SELECT * FROM mail_queue )
  LOOP
    sendMessage( msg.from, msg.to, msg.subject, msg.body );
    DELETE FROM mail_queue
     WHERE mail_queue_id = msg.mail_queue_id;
    commit;
  END LOOP;
END;

wheresendMessage实现了发送电子邮件的实际逻辑。我认为您可能希望使用utl_mailutl_smtp包来发送电子邮件,而不是使用utl_tcp,但当然,您可以使用utl_tcp. 然后,您将SendQueuedMessages使用dbms_jobdbms_scheduler包安排该过程。像这样的东西

DECLARE
  l_jobno PLS_INTEGER;
BEGIN
  dbms_job.submit( l_jobno,
                   'BEGIN SendQueuedMessages; END;',
                   sysdate + interval '1' minute,
                   'sysdate + interval ''1'' minute' );
  commit;
END;

SendQueuedMessages将创建一个每分钟运行该过程的作业。如果邮件服务器关闭,则该SendQueuedMessage过程将失败并且该作业会自动重新安排以稍后运行。第一次失败后,作业会在 1 分钟后再次运行。第二次失败后,2分钟后运行,然后4分钟、8分钟等,直到连续失败16次。如果您想在过程中捕获异常,您可以选择默认行为以外的其他行为SendQueuedMessages。由于作业失败会导致将失败写入警报日志,因此您的 DBA 可能会要求您处理异常并重新安排作业,以避免将不必要的数据写入警报日志。

于 2012-07-30T06:33:24.650 回答