6.9.1.1 qmgr_defer_todo:为延迟邮件清理待发送收件人列表

来源:互联网 发布:java jackson maven 编辑:程序博客网 时间:2024/06/09 18:33

/qmgr/qmgr_ defer.c106 /* qmgr_defer_todo - defer all todoqueue entries for specific site */107108 void   qmgr_defer_todo(QMGR_QUEUE *queue, DSN *dsn)109 {110    QMGR_ENTRY *entry;111    QMGR_ENTRY *next;112    QMGR_MESSAGE *message;113    RECIPIENT *recipient;114    int     nrcpt;115    QMGR_QUEUE *retry_queue;116117    /*118     * Sanity checks.119     */120    if (msg_verbose)121        msg_info("defer site %s: %s %s",122                  queue->name,dsn->status, dsn->reason);123124    /*125     * See if we can redirect the deliveries to the retry(8) delivery agent,126     * so that they can be handled asynchronously. If the retry(8) service is127     * unavailable, use the synchronous defer(8) server. With a large todo128     * queue, this blocks the queue manager for a significant time.129     */130    retry_queue = qmgr_error_queue(MAIL_SERVICE_RETRY, dsn);

130 qmgr_defer_todo优先使用retry MDA处理暂时无法发送的QMGR_ENTRY。对于retry MDA,将为每一种遇到的DSN错误建立一个QMGR_QUEUE。

 

qmgr_error_queue函数查找或创建retryMDA:

   /*    * Find or create transport.    */   if ((transport = qmgr_error_transport(service)) == 0)         return(0);

为每一种DSN错误类型建立一个QMGR_QUEEN:

/*    * Find or create queue.    */   nexthop = qmgr_error_nexthop(dsn);   if ((queue = qmgr_queue_find(transport, nexthop)) == 0)         queue= qmgr_queue_create(transport, nexthop, nexthop);


QMGR_QUEUE的名字根据DSN错误信息来构造:

/* qmgr_error_nexthop - computenext-hop information from problem description */char   *qmgr_error_nexthop(DSN *dsn){   char   *nexthop;    nexthop = concatenate(dsn->status, " ", dsn->reason,(char *) 0);   return (nexthop);}

qmgr_defer_todo会在qmgr_defer_transport或qmgr_deliver_update中被调用,分别代表两种错误:

4.3.0,错误信息为"mailtransport unavailable"

4.0.0,错误信息为”unknow error”

131132    /*133     * Proceed carefully. Queue entries may disappear as a side effect.134     */135    for (entry = queue->todo.next; entry != 0; entry = next) {136        next = entry->queue_peers.next;137        if (retry_queue != 0) {138             qmgr_entry_move_todo(retry_queue,entry);139             continue;140        }141        message = entry->message;142        for (nrcpt = 0; nrcpt < entry->rcpt_list.len; nrcpt++) {143             recipient =entry->rcpt_list.info + nrcpt;144             qmgr_defer_recipient(message,recipient, dsn);145        }146        qmgr_entry_done(entry, QMGR_QUEUE_TODO);147    }


135-147 循环该QMGR_QUEUE的todo QMGR_ENTRY_LIST,延迟发信。

 

这里对延迟分两种情况处理:存在retry MDA或不存在retry MDA的情况。这样的区分支持异步方式处理。

如果存在error模块,则使用qmgr_entry_move_todo函数将原QMGR_QUEUE的todo QMGR_ENTRY_LIST移动到retry MDA的以DSN错误代码为名称的QMGR_QUEUE的todo QMGR_ENTRY_LIST:

/*    * Create new entry, swap the recipients between the two entries,    * adjusting the job counters accordingly, then dispose of the old entry.    *    * Note that qmgr_entry_done() will also take care of adjusting the    * recipient limits of all the message jobs, so we do not have to do that    * explicitly for the new job here.    *    * XXX This does not enforce the per-entry recipient limit, but that isnot    * a problem as long as qmgr_entry_move_todo() is called only to bounce    * or defer mail.    */   dst_job = qmgr_job_obtain(message, dst_transport);   dst_peer = qmgr_peer_obtain(dst_job, dst_queue);   new_entry = qmgr_entry_create(dst_peer, message);   recipient_list_swap(&entry->rcpt_list,&new_entry->rcpt_list);


如果无法找到或建立retryQMGR_QUEUE,则调用qmgr_defer_recipient。qmgr_defer_recipient-> defer_append->defer_append_intern将直接联系bounce模块完成延迟处理工作。

148 }149150 /* qmgr_defer_recipient - deferdelivery of specific recipient */151152 void   qmgr_defer_recipient(QMGR_MESSAGE *message, RECIPIENT *recipient,153                                      DSN *dsn)154 {155    MSG_STATS stats;156157    /*158     * Update the message structure and log the message disposition.159     */160    message->flags |= defer_append(message->tflags,message->queue_id,161                                  QMGR_MSG_STATS(&stats, message),recipient,162                                   "none", dsn);163 }


无论是否存在retry MDA,最终都会调用qmgr_entry_done函数,该函数最终销毁无法使用的QMGR_ENTRY结构体。如果存在retry MDA,虽然continue语句会跳出本次循环,但qmgr_entry_move_todo函数中会调用qmgr_entry_done函数。如果不存在retry MDA,则会执行qmgr_entry_done函数,该函数的第二个参数接收

#define     QMGR_QUEUE_TODO    1                /* waiting for service */

#define QMGR_QUEUE_BUSY         2                /*recipients on the wire */

这两个选项,对于延迟发信,均使用选项QMGR_QUEUE_TODO。
0 1
原创粉丝点击